[原创]MT 4.0编程Step by Step
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自动交易程序,供参考。
//+------------------------------------------------------------------+
//| MakeGrid.mq4 |
//| Copyright ? 2005, hdb |
//| http://www.dubois1.net/hdb |
//+------------------------------------------------------------------+
#property copyright "Copyright ? 2005, hdb"
#property link "http://www.dubois1.net/hdb"
//#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 local variables. 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
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
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=0;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>=0;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(), MarketInfo(OrderSymbol(), MODE_BID), 5, Red );
//Close opened short positions
if ( type == OP_SELL ) result = OrderClose( OrderTicket(), OrderLots(), MarketInfo(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>=0;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 = MarketInfo(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
{
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 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);
}
//+------------------------------------------------------------------+
[ 本帖最后由 管理员No.6 于 2006-3-14 19:32 编辑 ]
2楼
这个只是入门的东东,有问题请在这个帖子下提,偶尽量回答。
谋定而后动
发表于:2006-03-14 11:40只看该作者
3楼
入。。。。。。。。门。。。。。。。。。。。。。。
哎,又浪费一个小时,我为什么什么事情都那么认真?以后尽量不上论坛了。
4楼
自动交易系统的测试
很多人都想用历史数据测试自己的自动交易系统结果怎么样。
在MT的View菜单下,有一个Strategy tester。
选定自己的交易系统,设定好币种,历史数据的时间周期,交易系统的属性,勾上Recalculate,设定时间范围,点Start按钮即开始测试。
特别强调的是,由于历史数据不能反映内部的波动情况,测试中可以选择三种插值方式,但是因为要使用插值,测试结果可能是不准确的,尤其是在以下两种情况下:
(1) 有止损的策略
(2) 使用的TimeFrame比较大
发表于:2006-03-14 11:45只看该作者
5楼
太难了,俺不会,嘿嘿
云在青天 水在瓶
6楼
原帖由 奔跑中 于 2006-3-14 19:45 发表 太难了,俺不会,嘿嘿
发表于:2006-03-14 11:55只看该作者
7楼
原帖由 一苇渡江 于 2006-3-14 19:49 发表 没关系,我教你。:handshake:handshake:handshake 只收你利润的一半做学费。:lol:lol:lol
云在青天 水在瓶
发表于:2006-03-14 11:59只看该作者
8楼
收藏了,可惜我E文太次了。
进程:开户->理性分析师->理性投注师
发表于:2006-03-14 12:09只看该作者
9楼
谢谢,收藏了慢慢学
征服必然王国! 探索自由世界!
发表于:2006-03-14 12:48只看该作者
10楼
留名收藏,不晓得楼主给人编一个收多少MM?
11楼
原帖由 梦靥 于 2006-3-14 20:48 发表 留名收藏,不晓得楼主给人编一个收多少MM?
发表于:2006-03-14 13:13只看该作者
12楼
大老,有空举个例,一句一个中文的,随便什么指标。。,
不胜感谢!!!
13楼
原帖由 afeng 于 2006-3-14 21:13 发表 大老,有空举个例,一句一个中文的,随便什么指标。。, 不胜感谢!!!
发表于:2006-03-14 14:07只看该作者
14楼
还是懵懂
韬客社区www.talkfx.co
15楼
原帖由 道拉德 于 2006-3-14 22:07 发表 还是懵懂
发表于:2006-03-14 14:16只看该作者
16楼
好东西啊,顶
建立任何部位都必须让自己明天能够继续交易
发表于:2006-03-14 14:17只看该作者
17楼
哦!
已好久没有编过程了!怕都生疏了
发表于:2006-03-14 14:49只看该作者
18楼
请教用第二个例调试历史数据,可以用C的fopen()把返回值写到一个文件吗?
我没学过作图函数。
进程:开户->理性分析师->理性投注师
19楼
原帖由 望云 于 2006-3-14 22:49 发表 请教用第二个例调试历史数据,可以用C的fopen()把返回值写到一个文件吗? 我没学过作图函数。
发表于:2006-03-14 15:27只看该作者
20楼
原帖由 一苇渡江 于 2006-3-14 21:53 发表 找了一个根据均线交易的例子,我自己择主要的加了一些中文注释,看看有没有帮助。 //+------------------------------------------------------------------+ //| ...