第二節MQL4常用語句

在上一節課中我們新建了一個腳本,介紹了一些基本的知識。本節課我們要新建我們的第一個EA,了解一下EA的運行方式,學會用一些常用的語句。

1.新建第一個EA

和新建腳本一樣,我們需要點擊左上角的新建菜單,只不過這一次我們要新建的是一個EA,如下圖:


創建好EA後,我們會發現新的EA代碼主要有三部分組成:OnInit()函數、OnDeint()函數、OnTick()函數,如以下代碼:


 #property copyright "Copyright 2019, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #property strict int OnInit () { return(INIT_SUCCEEDED); } void OnDeint (const int reason) { } void OnTick () { }


這三部分分別是什麼意思呢,第一個函數OnInit()是初始化函數,只在EA剛加載的時候運行一次,一些前期的工作可以放到這裡來做,比如判斷賬戶是否可以使用該EA等,如果初始化成功就會返回INIT_SUCCEEDED,此時EA就會轉移到OnTick()函數運行,如果不成功則程序結束。

OnTick()函數在當前品種每個Tick報價來的時候會運行一次,也就是說只要當前品種價格變動,OnTick()函數就會運行一次,在一個Tick下,EA可以做很多事,比如瞬時開平倉、掛單、移動掛單價格、移動止損止盈等,這也是為什麼EA能做到很多人很難做到的事,也是其優點之一。

OnDeint()函數在EA退出的時候會運行一次,我們運行EA時,很多時候會讓EA在圖表上顯示很多信息,也會在圖上畫線之類的,當我們退出EA時往往想把這些線去掉以方便看圖表,這時就要用到該函數來刪除圖表上的內容。

目前我們還用不到OnInit()函數和OnDeinit()函數,可以暫時將他們刪除。接下來我們在EA中寫一些常用的語句,試試我們的新EA。

2.輸出語句

在上節課中我們知道了Print()函數的使用方法,下面我們在EA中試一下:


 int a=1; void OnTick () { int b=2; a++; Print("a+b="+(string)(a+b)); }


編譯運行後我們可以看到EA的輸出如下圖:



可以看到,由於a是全局變量,它只初始化一次,因此每個Tick過來之後,a的數值不會回到原來的數值而是加了1,所以a+b的數值也會加1。

如果我們需要在同一行輸出多個內容怎麼辦?我們可以在後面用”+”號將兩個輸出連起來,如下:


 int a=1; void OnTick () { int b=2; a++; Print("a+b="+(string)(a+b)+ " ab="+(string)(ab)+ "\na-b="+(string)(ab)); }


編譯運行後我們可以看到EA的輸出如下圖:



我們將兩個內容連起來了。注意,對於Print函數,在其他語言中都有用的換行符號”\n”是不起作用的,Print的輸出只能在一行內。

除了Print,我們還可以用Comment函數實現輸出,如以下代碼所示:


 int a=1; void OnTick () { int b=2; a++; Comment("a+b="+(string)(a+b)+ " ab="+(string)(ab)+ "\na-b="+(string)(ab)); }


以上語句的輸出如下圖所示:



可以看到在圖表的左上角顯示了我們的輸出結果,而且我們注意到,”\n”起到了換行的作用。

第三種輸出方式,我們可以用MessageBox來輸出,代碼如下:


 int a=1; void OnTick () { int b=2; a++; MessageBox("a+b="+(string)(a+b)+ " ab="+(string)(ab)+ "\na-b="+(string)(ab)); }


輸出結果如下:



可以看到我們輸出了一個彈窗,這對於一些半自動交易系統來說是非常有用的,當達到一定的條件時,程序可以自動提示,然後由人工判斷是否可以入場。

接下來我們來試著改一下彈窗的標題和彈窗的選項,代碼如下:


 int a=1; void OnTick () { int b=2; a++; MessageBox("a+b="+(string)(a+b),"计算结果",1); }


輸出結果如下:



可以看到,我們輸出的標題變為了”計算結果”,選項中加了一個”取消”的選項,因此MesageBox這個函數第一部分是輸出的內容,第二部分是彈窗的標題,第三部分是彈窗的選項。

那麼彈窗都有哪些選項呢?我們打開MQL4幫助文件,搜索MessageBox函數,如下圖:



可以看到,若函數的第三部分是0,則代表僅有一個”確定”選項;1代表有一個”確定”選項以及一個”取消”選項;2代表”中止”/”重試”/”忽略”,有三個選項;3代表”是”/”否”/”取消”,也有三個選項;4代表”是”/”否”,只有兩個選項,5代表”重試”/”取消”,6代表”取消”/”重試”/”繼續”。至於怎麼使用它們,會在以後的課程中介紹給大家。

3.邏輯判斷

接下來介紹一下簡單且最常用的邏輯判斷函數,if和else,if的作用是,當條件成立時就執行if內的語句,如以下代碼:


 int a=1; void OnTick () { int b=3; int c=1; if (a<5) { a=a+b; } else if (a>=5 && a<=7) { a=a+c; } else { a=ac; } Print("a="+(string)(a)); }


以上代碼的意思是,如果a<5,那麼當有報價過來的時候會激發OnTick()函數,將a+b的值重新賦給a;否則的話(即a>=5)如果a>=5且a<=7,那麼將a+c的值賦給a;再不然(即a>7),則將ac的值賦給a。根據這個邏輯,那麼第一的輸出應該是1+3=4,第二次是4+3=7,第三次是7+1=8,第四次是8-1=7,往後都在7和8之間來回輸出。

我們看一下我們的EA輸出是否符合我們的邏輯預期,輸出如下:



輸出沒有問題。

上例中已經講了兩個條件需要同時成立時才能執行語句的”與”邏輯,即以上代碼中的”&&”,另外有的時候我們需要判斷,如果兩個條件中的任意一個條件成立那我們就執行,或說條件不成立我們就執行。以下代碼做個示例:


 int a=1; void OnTick () { int b=1; int c=1; if (b<1 || !(c>1)) { a=a+1; } Print("a="+(string)(a)); }


以上的語句的意思是,只要滿足“b<1”或者“非c>1”(即c<=1)的條件,則將a加1並輸出,我們可以看到“或”邏輯用的符號是“||”,“非”邏輯用的符號是“!”,看一下輸出結果:



可以看到輸出結果是符合我們的預期的。

雖然邏輯判斷語句很簡單,但這是寫EA時最重要的函數之一,很多時候進行入場條件的判斷以及出場條件的判斷都要用到它,因此這個是最基本的東西。

4.字符串處理

字符串處理函數也是一類比較重要的函數,這一類函數在判斷交易品種的時候特別有用。比如說,我們要做交叉盤,計算交叉盤的盈虧的時候又需要用到直盤貨幣對的匯率,這個時候我們怎麼自動查詢直盤貨幣對的匯率呢?

這個時候我們需要把交叉貨幣對分成前後兩個部分,比如EURGBP,我們要把它先分解成EUR以及GBP,然後再將字符串與USD拼接,再查詢新拼接到的產品的匯率,比如說將EUR與USD拼接成EURUSD,再在所有產品中查詢名字叫做”EURUSD”的品種的價格。

那麼首先,我們先實現將產品的字符串分成兩部分,第一部分字符串,3個字符,第二部分字符串也是三個字符,採用StringSubstr ()函數來截取字符串。打開幫助文件我們可以看一下這個函數有什麼功能



如上圖,這個函數需要輸入的第一個變量是要處理的字符串;第二個變量是截取的開始位置編號注意字符串中的第一個字符的位置編號為0,第二個字符編號為1,往後順延;第三個變量是截取的字符的個數。

下面我們將字符串”EURGBP”截取為兩段,代碼如下:


 void OnTick () { string a="EURGBP"; string b="”; string c="”; b=StringSubstr(a, 0, 3); c=StringSubstr(a, 3, 3); Print("b="+b+" c=" +c); }


這段代碼的意思是在字符串a中,從其位置編號為0的字符往後數3個字符,將這3個字符賦給b,既將a的前三個字符賦給b。由於a的第四個字符位置編號為3,那麼我們就從位置編號為3的字符往後數3個,將這些字符賦給c,最終輸出的結果如下:



可以看出我們做到了截取字符串的處理。

接下來,我們要組合字符串,將其組合成直盤的貨幣對,這時可以簡單地使用加法將字符串粘合,比如我們的字符串為a=”EUR”,那麼我們直接將它加上”USD”,即a=a+”USD”,a就成為了”EURUSD”。

我們知道,有些直盤貨幣對是美元在前的,比如說”USDJPY”,如果交叉貨幣對裡面出現了日元,那麼直接加上”USD”你輸出的結果就成了”JPYUSD”了,對於一般的平台,這個貨幣對是不存在的。

於是很苦惱,現在我們想要一個隨便輸入一個交叉貨幣對,都能找到直盤貨幣對的程序,怎麼做呢?

我們可以事先定義好直盤貨幣對,然後再判斷我們粘合後的貨幣對和事先定義好的是否一至,這就要用到循環語句了。

5.循環

循環語句在任何一門計算機語言中都是最基本最重要的內容,MQL4也不例外。 MQL4裡的循環語句和C語言非常接近,一般用到的語句有for循環,while循環以及do while循環,控制循環的語句也有break和continue。接下來以一個案例介紹一下MQL4中如何使用這些循環,代碼如下:

 void OnTick () { int a=0; int b=0; int c=0; int d=1; int i; //for循环for(i=0;i<=10;i++) { a=a+d; } //while循环i=0; while(i<=10) { b=b+d; i++; } //do while循环i=0; do { b=b+d; i++; } while(i<=10) }


由上例可以看出,採用for循環是需要輸入循環次數的,但是相對來說for循環簡介一點。 while循環中的條件是該循環繼續下去的判斷條件,當該條件不成立時則跳出循環,如上例,這個while循環在i<=10時會繼續循環,當進行到i>10為時,循環終止了。 do while循環也是一樣的。

for循環不怎麼方便的地方在於它本身必須要指定循環的次數,如果面對的是一個在接近無窮多的數據中查找想要的數據的問題,那麼這個循環的次數就不好指定了,設小了就很容易因為循環次數到了而跳出了循環導致查詢的結果不對。而while和do while不會,這兩個可以根據你的查找條件來跳出循環,不用指定循環次數。一般來說循環採用for循環,結構清晰,但是涉及到查詢類的問題建議用while和do while循環。

知道了循環的用法,接下來我們便可以解決在字符串處理一節中遺留下來的問題了,即輸入任意一個交叉貨幣對名稱,將其分解成兩個直盤貨幣對的名稱。代碼如下:


 void OnTick () { string symbol[7]; symbol[0]="EURUSD";symbol[1]="GBPUSD";symbol[2]="AUDUSD";symbol[3]="NZDUSD";symbol[4]="USDCHF";symbol[5]="USDJPY";symbol[6]="USDCAD"; string a="EURJPY"; string b="”; string c="”; int i; int kaiguan=0; b=StringSubstr(a, 0, 3); c=StringSubstr(a, 3, 3); string d= b+”USD” ; for(i=0;i<=6;i++) { if(d==symbol[i]) { kaiguan=1; b=b+”USD”; break; } } if(kaiguan==0) { b=”USD”+b; } kaiguan=0; string e= c+”USD” ; for(i=0;i<=6;i++) { if(e==symbol[i]) { kaiguan=1; c=c+”USD”; break; } } if(kaiguan==0) { c=”USD”+c; } Print("第一个货币对为"+b); Print("第二个货币对为"+c); }


以上代碼中先定義了所有的直盤貨幣對的名稱,然後再將輸入的交叉貨幣對分解成兩部分,然後在後面加上”USD”並和之前定義好的直盤貨幣對比對,如果比對是正確的,那麼也就是說我們在後面加上的”USD”是對的,反之則在前面加上”USD”。

輸出的結果如下圖:



以上便是MQL4的一些基本語法,在以後這些語法將經常用到,如果把學習MQL4類比於學英語,那這幾個語法就是英文字母了,學會了後面就容易多了。


更多內容請關注公眾號【火象】~