品牌外汇EA:MT4.0编程函数库 | 有效期至长期有效 | 最后更新2019-01-10 18:46 |
浏览次数808 |
外汇EA:MT4.0编程函数库
MT4.0和3.x相比,编程语言迥然不同,基本上是C语言的翻版,所以有一些C语言基础是很容易学会MT编程的。
MT4.0可以编写的程序有好几类,主要是自动交易程序和指标,估计大家都是为了给自己的投资策略,由于我的精力有限,所以接下来只介绍自动交易程序。
1. MT程序的语法
MT程序既然是C语言的翻版,语法和C语言当然很接近了,用有限的篇幅来说明其语法似乎是一个不能完成的任务,我这里只能告诉大家如何去学习。
语法说明可以在meta Editor的帮助中找到,在工具栏上点MQL Navigator,就会弹出MT编程的导航,其中Dictionary就是语言和函数库的帮助。
在这个树状帮助目录下,语法的说明在Basic下,主要包括Syntax, Data type, Operations expressions, Operators, Functions, Variables, Preprocessor
如果会C的话,粗略看一下即可,如果不会,结合例程学习一遍吧。
由于帮助基本是英文的,所以刚开始学还是有难度的,不过没有办法,我也帮不上忙,大家有问题就提吧,我尽量回答。啥时候能出个中文版的就好了。
学习的时候,从网上搜一些现成的程序进行学习和修改是加快学习的一个办法,上一次我贴的Grid的交易程序就是一个很好的学习的例子。
2. 函数库
MT的函数库帮助进行了分类,看起来还是比较方便的。这里也没有办法详细介绍,做一个扼要介绍。
还是在帮助的Dictionary下,看这些帮助要考验一下大家的英文,特别要涉及到金融和计算机专业英语。
包括以下几类:
(1) Stardard constants
也就是系统定义的标准常量,主要是一些枚举类型和窗口常量等,一般先不用管它,在别的地方会链接过来。
(2) Predifined variables
一些系统常量,包括买入价,卖出价,最高、最低价等,还是很有用的,不过不太多,挨个儿看一下吧。
(3) Account Information
账户有关的函数
(4) Array functions
数组处理函数。
(5) Common functions
常用处理函数。
(6) Conversion functions
转换函数,主要是字符串和主要类型之间的转换函数。
(7) Custom Indicators
编写自定义指标用到的函数,如果不编写自定义指标的话,可以不管它。
(8) Date Time functions
时间日期有关的函数
(9) File functions
文件处理函数
(10) Globle variables
全局变量有关的处理函数。
(11) Math Trig
数学计算函数
(12)Object functions
对象处理函数,主要是在图表中处理对象的函数,对象是指直线、文本等。
(13) String functions
字符串处理函数。
(14) Technical indicators
技术指标函数,相信大家一定会经常用到的。大家通过指标的英文,应该比较容易看出来谁是谁。
(15) Trading functions
交易函数。这一类对自动交易系统是很重要的。
(16) Window functions
窗口处理函数,基本不需要用到。
3. 创建程序
在MT的程序组中,有一个meta Editor,这就是MT的编译器,还是很容易上手的。用过Visual Studio C++的人一看,有点熟,对吧?
首先,点击菜单File- New,弹出对话框,程序类型选择Expert Advisor,后面按导航操作输入名称即可。
这样一个简单的MT空白交易程序就创建了,点按钮Compile或直接按快捷键F5就可以编译通过了。因为是空白的,这时候它什么也不能干。
注意:自动交易程序一定要存放在安装目录下的Experts子目录。
4. 修改
(1)全局变量
在程序的开头,可以定义一下全局变量。前面加extern的全局变量的值,在自动交易程序启动的时候可以直接在MT改,不需要重新编译。
(2)入口函数
MT程序的调用入口是start()函数,和C程序的main()函数是一样的,一般就在这里写处理过程即可。
(3) 子函数
比较复杂的过程,可以写子函数,在start()函数里调用子函数。
5. 例程:以下是在MT官方网站的论坛下hdb写的Grid自动交易程序,供参考。
#property copyright n.com target=_blank >外汇联盟 www.FXunion.com QQ群144033
#property link
//#property version 1.8
// DISCLAIMER ***** importANT NOTE ***** READ BEFORE USING *****
// This expert advisor can open and close real positions and hence do real trades and lose real money.
// This is not a 'trading system' but a simple robot that places trades according to fixed rules.
// The author has no pretentions as to the profitability of this system and does not suggest the use
// of this EA other than for testing purposes in demo accounts.
// Use of this system is free - but u may not resell it - and is without any garantee as to its
// suitability for any purpose.
// By using this program you implicitly acknowledge that you understand what it does and agree that
// the author bears no responsibility for any losses.
// Before using, please also check with your broker that his systems are adapted for the frequest trades
// associated with this expert.
// 1.8 changes
// made wantLongs and wantShorts into localvariables. Previously, if u set UseMACD to true,
// it did longs and shorts and simply ignored the wantLongs and wantShorts flags.
// Now, these flags are not ignored.
// added a loop to check if there are 'illicit' open orders above or below the EMA when the limitEMA34
// flag is used. These accumulate over time and are never removed and is due to the EMA moving.
// removed the switch instruction as they dont seem to work - replaced with if statements
// made the EMA period variable
//
//
// modified by cori. Using OrderMagicNumber to identify the trades of the grid
extern int uniqueGridMagic = 11111; // Magic number of the trades. must be unique to identify
// the trades of one grid
extern double Lots = 0.1; //
extern double GridSize = 6; // pips between orders - grid or mesh size
extern double GridSteps = 12; // total number of orders to place
extern double TakeProfit = 12 ; // number of ticks to take profit. normally is = grid size but u can override
extern double StopLoss = 0; // if u want to add a stop loss. normal grids dont use stop losses
extern double UpdateInterval = 1; // update orders every x minutes
extern bool wantLongs = true; // do we want long positions
extern bool wantShorts = true; // do we want short positions
extern bool wantBreakout = true; // do we want longs above price, shorts below price
extern bool wantCounter = true; // do we want longs below price, shorts above price
extern bool limitEMA = false; // do we want longs above ema only, shorts below ema only
extern int EMAperiod = 34; // the length of the EMA.. was previously fixed at 34
extern double GridMaxOpen = 0; // maximum number of open positions : not yet implemented..
extern bool UseMACD = false; // if true, will use macd 0 for longs only, macd 0 for shorts only
// on crossover, will cancel all pending orders. This will override any
// wantLongs and wantShort settings - at least for now.
extern bool CloseOpenPositions = false;// if UseMACD, do we also close open positions with a loss?
extern bool doHouseKeeping = true; // just a test
// modified by cori. internal variables only
string GridName = Grid // identifies the grid. allows for several co-existing grids
double LastUpdate = 0; // counter used to note time of last update
#property copyright n.com target=_blank >外汇联盟 www.FXunion.com QQ群144033
#property link
int init()
{
//----
#property show_inputs // shows the parameters - thanks Slawa...
//----
// added my corri and removed by hdb!! lol.. just to stay compatible with open grids...
// GridName = StringConcatenate( Grid , Symbol() );
return(0);
}
//+------------------------------------------------------------------------+
//| tests if there is an open position or order in the region of atRate |
//| will check for longs if checkLongs is true, else will check |
//| for shorts |
//+------------------------------------------------------------------------+
bool IsPosition(double atRate, double inRange, bool checkLongs )
{
int totalorders = OrdersTotal();
for(int j=0;j {
OrderSelect(j, SELECT_BY_POS);
// modified by cori. Using OrderMagicNumber to identify the trades of the grid // hdb added or gridname for compatibility
if ( OrderSymbol()==Symbol() ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) ) // only look if mygrid and symbol...
{ int type = OrderType();
if (MathAbs( OrderOpenPrice() - atRate ) (inRange*0.9)) // dont look for exact price but price proximity (less than gridsize) - added 0.9 because of floating point errors
{ if ( ( checkLongs ( type == OP_BUY || type == OP_BUYLIMIT || type == OP_BUYSTOP ) ) || (!checkLongs ( type == OP_SELL || type == OP_SELLLIMIT || type == OP_SELLSTOP ) ) )
{
return(true);
}
}
}
}
return(false);
}
//+------------------------------------------------------------------------+
//| cancells all pending orders |
//+------------------------------------------------------------------------+
void CloseAllPendingOrders( )
{
int totalorders = OrdersTotal();
bsp; for(int j=totalorders-1;j j--) // scan all orders and positions...
{
OrderSelect(j, SELECT_BY_POS);
// modified as per cori. Using OrderMagicNumber to identify the trades of the grid // hdb added or gridname for compatibility
if ( OrderSymbol()==Symbol() ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) ) // only look if mygrid and symbol...
{
int type = OrderType();
if ( type 1 ) bool result = OrderDelete( OrderTicket() );
}
}
return;
}
//+------------------------------------------------------------------------+
//| cancells all pending orders and closes open positions |
//+------------------------------------------------------------------------+
void CloseOpenOrders()
{
int total = OrdersTotal();
for(int i=total-1;i i--)
{
OrderSelect(i, SELECT_BY_POS);
int type = OrderType();
bool result = false;
// modified by cori. Using OrderMagicNumber to identify the trades of the grid // hdb added or gridname for compatibility
if ( OrderSymbol()==Symbol() ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) ) // only look if mygrid and symbol...
{
//Close opened long positions
if ( type == OP_BUY ) result = OrderClose( OrderTicket(), OrderLots(), 骗子Info(OrderSymbol(), MODE_BID), 5, Red );
//Close opened short positions
if ( type == OP_SELL ) result = OrderClose( OrderTicket(), OrderLots(), 骗子Info(OrderSymbol(), MODE_ASK), 5, Red );
//Close pending orders
if ( type 1 ) result = OrderDelete( OrderTicket() );
}
}
return;
}
//+------------------------------------------------------------------------+
//| cancells all open orders which fall on the wrong side of the EMA |
//+------------------------------------------------------------------------+
void CloseOrdersfromEMA( double theEMAValue )
{
int totalorders = OrdersTotal();
for(int j=totalorders-1;j j--) // scan all orders and positions...
{
OrderSelect(j, SELECT_BY_POS);
if ( OrderSymbol()==Symbol() ( (OrderMagicNumber() == uniqueGridMagic) || (OrderComment() == GridName)) ) // only look if mygrid and symbol...
{
int type = OrderType();
bool result = false;
//if (type 1) Print(type, ,theEMAValue, ,OrderOpenPrice());
if ( type == OP_BUYLIMIT OrderOpenPrice() = theEMAValue ) result = OrderDelete( OrderTicket() );
if ( type == OP_BUYSTOP OrderOpenPrice() = theEMAValue ) result = OrderDelete( OrderTicket() );
if ( type == OP_SELLLIMIT OrderOpenPrice() = theEMAValue ) result = OrderDelete( OrderTicket() );
if ( type == OP_SELLSTOP OrderOpenPrice() = theEMAValue ) result = OrderDelete( OrderTicket() );
}
}
return;
}
//+------------------------------------------------------------------+
//| script program start function |
//+------------------------------------------------------------------+
int start()
{
//----
int i, j,k, ticket, entermode, totalorders;
bool doit;
double point, startrate, traderate;
//---- setup parameters
if ( TakeProfit = 0 ) //
{ TakeProfit = GridSize; }
bool myWantLongs = wantLongs;
bool myWantShorts = wantShorts;
//----
if (MathAbs(CurTime()-LastUpdate) UpdateInterval*60) // we update the first time it is called and every UpdateInterval minutes
{
LastUpdate = CurTime();
point = 骗子Info(Symbol(),MODE_POINT);
startrate = ( Ask + point*GridSize/2 ) / point / GridSize; // round to a number of ticks divisible by GridSize
k = startrate ;
k = k * GridSize ;
startrate = k * point - GridSize*GridSteps/2*point ; // calculate the lowest entry point
double myEMA=iMA(NULL,0,EMAperiod,0,MODE_EMA,PRICE_CLOSE,0);
if (limitEMA)
{
if (doHouseKeeping) CloseOrdersfromEMA(myEMA);
}
if ( UseMACD )
{
double Macd0=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
double Macd1=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
double Macd2=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,2);
if( Macd0 0 Macd1 0 Macd2 0) // cross up
{
CloseAllPendingOrders();
if ( CloseOpenPositions == true ) { CloseOpenOrders(); }
}
if( Macd0 0 Macd1 0 Macd2 0) // cross down
nbp; {
CloseAllPendingOrders();
if ( CloseOpenPositions == true ) { CloseOpenOrders(); }
}
myWantLongs = false;
myWantShorts = false;
if( Macd0 0 Macd1 0 Macd2 0 wantLongs ) // is well above zero
{
myWantLongs = true;
}
if( Macd0 0 Macd1 0 Macd2 0 wantShorts ) // is well below zero
{
myWantShorts = true;
}
}
for( i=0;i {
traderate = startrate + i*point*GridSize;
if ( myWantLongs (!limitEMA || traderate myEMA))
{
if ( IsPosition(traderate,point*GridSize,true) == false ) // test if i have no open orders close to my price: if so, put one on
{
double myStopLoss = 0;
if ( StopLoss 0 )
{ myStopLoss = traderate-point*StopLoss ; }
if ( traderate Ask )
{ entermode = OP_BUYSTOP; }
else
{ entermode = OP_BUYLIMIT ; }
if ( ((traderate Ask ) (wantBreakout)) || ((traderate = Ask ) (wantCounter)) )
{
// modified by cori. Using OrderMagicNumber to identify the trades of the grid
ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate+point*TakeProfit,GridName,uniqueGridMagic,0,Green);
}
}
}
if ( myWantShorts (!limitEMA || traderate myEMA))
{
if (IsPosition(traderate,point*GridSize,false)== false ) // test if i have no open orders close to my price: if so, put one on
{
myStopLoss = 0;
if ( StopLoss 0 )
{ myStopLoss = traderate+point*StopLoss ; }
if ( traderate Bid )
{ entermode = OP_SELLLIMIT; }
else
{ entermode = OP_SELLSTOP ; }
if ( ((traderate Bid ) (wantBreakout)) || ((traderate = Bid ) (wantCounter)) )
{
// modified by cori. Using OrderMagicNumber to identify the trades of the grid
ticket=OrderSend(Symbol(),entermode,Lots,traderate,0,myStopLoss,traderate-point*TakeProfit,GridName,uniqueGridMagic,0,Red);
}
}
}
}
}
return(0);
}
//+------------------------------------------------------------------+
自动交易系统的测试
很多人都想用历史数据测试自己的自动交易系统结果怎么样。
在MT的View菜单下,有一个Strategy tester。
选定自己的交易系统,设定好币种,历史数据的时间周期,交易系统的属性,勾上Recalculate,设定时间范围,点Start按钮即开始测试。
特别强调的是,由于历史数据不能反映内部的波动情况,测试中可以选择三种插值方式,但是因为要使用插值,测试结果可能是不准确的,尤其是在以下两种情况下:
(1) 有止损的策略
(2) 使用的Timeframe比较大
找了一个根据均线交易的例子,我自己择主要的加了一些中文注释,看看有没有帮助。
//+------------------------------------------------------------------+
//| Moving Average.mq4 |
//| Copyright ?2005, metaQuotes Software Corp. |
//| http://fxunion.com |
//+------------------------------------------------------------------+
#define MAGICMA 20050610
// extern的全局变量,编译后可以直接在MT中修改
extern double Lots = 0.1;
extern double MaximumRisk = 0.02;
extern double DecreaseFactor = 3;
extern double MovingPeriod = 12;
extern double MovingShift = 6;
//+------------------------------------------------------------------+
//| 入口函数,程序从这里开始运行 |
//+------------------------------------------------------------------+
void start() {
//----
if(Bars 100 //如果历史数据不足100根K线
|| IsTradeAllowed()==false) // 或者系统目前不允许交易
return; // 退出
//----
if(CalculateCurrentOrders(Symbol())==0)// 调用子函数CalculateCurrentOrders检查现有仓位,是否需要建仓
CheckForOpen(); // 调用子函数CheckForOpen开始建立仓位
else
CheckForClose(); // 否则检查是否需要平仓
//----
}
//+------------------------------------------------------------------+
//| 检查现有仓位|
//+------------------------------------------------------------------+
int CalculateCurrentOrders(string symbol)
{
int buys=0,sells=0;
//----
for(int i=0;i {
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) // 如果获取Order失败,则退出
break;
if(OrderSymbol()==Symbol() OrderMagicNumber()==MAGICMA) // 获取仓位成功
{
if(OrderType()==OP_BUY) buys++; // 如果是买单,买单计数器加一
if(OrderType()==OP_SELL) sells++; // 如果是卖单,卖单计数器加一
}
}
//---- return orders volume
if(buys 0) return(buys); // 有至少一张买单,返回买单数量
else return(-sells); // 否则,返回卖单数量的负值
}
//+------------------------------------------------------------------+
//| 计算最优仓位
//+http://blog.sina.com.cn/zhouxiaoyin18---------------------+
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);
//---- calcuulate number of losses orders without a break
if(DecreaseFactor 0)
{
for(int i=orders-1;i 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);
}
//---- return lot size
if(lot 0.1) lot=0.1;
return(lot);
}
//+------------------------------------------------------------------+
//| 检查是否建仓 |
//+------------------------------------------------------------------+
void CheckForOpen()
{
double ma;
int res;
//---- go trading only for first tiks of new bar
if(Volume[0] 1) return;
//---- 指标调用,iMA就是均线(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]ma)
{
res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0, ,MAGICMA,0,Blue);
return;
}
//----
}
//+------------------------------------------------------------------+
//| 检查是否平仓 |
//+------------------------------------------------------------------+
void CheckForClose()
{
double ma;
//---- go trading only for first tiks of new bar
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;
//---- check order type
if(OrderType()==OP_BUY)
{
if(Open[1] ma Close[1] break;
}
if(OrderType()==OP_SELL)
{
if(Open[1]ma) OrderClose(OrderTicket(),OrderLots(),Ask,3,White);
break;
}
}
//----
}