面向初學者的 MQL4 語言系列之1——MQL4 語言入門
簡介
本系列的文章主要針對的是完全不懂程式設計,但想要在最短的時間內花費最少的精力盡快了解 MQL4 語言的交易者。如果您看到“面向物件”或“三維陣列”這類詞語就覺得頭痛,那麼這篇文章正是您需要的良方。這些課程的設計旨在最快出成果。內容也通俗易懂。我們在理論方面不會有太深的研究,但從第一課起就已能獲得實際的收益了。
建議
如果您之前從未做過程式設計工作,第一次閱讀某些案例時,您會發現很難懂其中的意思。慢慢再看一遍文字,仔細思考每個句子。您終會豁然開朗,因為這實際上真的不難。在理解之前的資訊後,方可進行下一步。研究程式碼示例。根據您學到的內容編寫自己的程式碼示例。
首先要了解 MQL4
讓我們先來看一下可以用這種語言做什麼。它主要用於建立指令碼、自定義指標、EA 和庫:
- 指令碼就是命令序列,即您每請求一次才執行一次的程式。它們可替代您每天在交易中執行的操作。例如當您開訂單時。它們也可執行特定功能,例如分析圖表和生成統計資訊。
- 定製指標是技術指標,主要作為內建指標的補充。它們用於開發圖表或其他可視資訊。和指令碼不同的是,自定義指標在每次價格變動(即每跳動一次)時執行一次。顯示什麼指標只取決於您。它可以是一個沒什麼作用的竇道圖,也可以是幫助您探尋市場方向的強大工具。例如,如果您確切地知道市場在什麼時候、哪些情況下會趨於平盤態勢,您可以將其編寫到一個指標裡。
- Expert Advisor是繫結到任何金融工具上的機械交易系統。與自定義指標類似,每跳動一次,expert advisor 就作用一次,其與指標的不同之處在於,它們可以通知您市場情況(例如,提供某些買入或賣出建議)或自己進行交易,無需您的幫助。終端可支援策略測試,從而快速評估您的 expert advisor 的盈利能力。您可以用 MQL4 語言描述您的策略,而終端會堅定不移地遵循您的所有指示。
- 庫是用於執行特定任務的函式集合。例如,您的某個 EA 可能使用了特殊的數學函式來決定買入和賣出的時機。
本文中我們將學習編寫通用指令碼。為此我們使用了一個特殊的程式 - MetaEditor 4。要啟動它,在開啟的自定義終端上按 F4 鍵。要新建一個指令碼,單擊 MetaEditor 4 選單中的“檔案”->“新建”按鈕,用用“Ctrl+N”按鈕:
在顯示的視窗中,選擇要建立的專案。選擇“指令碼”,然後單擊“下一步”:
在下一個視窗中,在名稱欄位中名稱欄位中鍵入指令碼名稱。在作者欄位中新增您的姓名並在連結欄位中鍵入指令碼名稱。然後單擊確定:
之後會看到一個新視窗,這是您將使用的最重要的工具。它顯示原始文字:
請注意,即便是一個空白的、不可執行的指令碼也包含著一個程式碼。現在萬事俱備,開始程式設計。但很遺憾,接下來該怎麼做,您一點頭緒都沒有。讓我們試著改變這種狀況。
原始碼、編譯和其他
您應該瞭解一件重要的事情。在 MetaEditor 中編寫的是原始碼。即,它是一個命令序列,而終端將一個個往下執行這些命令。但終端無法執行原始碼。原始碼對您來說是可以理解的,但 MetaTrader 理解不了。要終端可以理解原始碼,應將原始碼“翻譯”成合適的“語言”。要進行“翻譯”,在 MetaEditor 中按下F5鍵。之後,原始碼將被編譯成一個執行檔案。編譯是一種將您編寫並可理解的原始碼“翻譯”成 MetaTrader 可理解並可執行的特殊檔案的過程。自己試一試。新建一個名為“Test1”的指令碼,但不要編譯。使用“瀏覽器”開啟終端,進入“指令碼”資料夾。您會看到並沒有名為“Test1”的指令碼:
現在編譯此指令碼(F5 鍵):
再次進行終端。“Test1”指令碼出現了。
在終端瀏覽器中雙擊該指令碼名稱,該指令碼將開啟。但什麼都不會發生,因為指令碼是空的。
現在您應該已經瞭解編寫指令碼的流程是什麼樣的了:編寫原始碼,編譯指令碼,在終端中開啟指令碼,檢視結果,更改特定程式碼,編譯,檢視...就這麼迴圈,直到得到想要的結果。
應該在哪裡編寫指令碼?
您應該已經看到,空指令碼包含一個特定程式碼。但應該將原始碼寫到哪裡?什麼原始碼有用?應該將原始碼寫在int start(){行與 return(0);}行之間,如圖中所示:
在這裡編寫我會提供給您的所有東西,這些都會起到作用。稍後我們將詳細說明這些行的意義。
變數
什麼是變數?試著自己找到答案,我會提供一些幫助。您現在幾歲?五年後您幾歲?看,您的年齡就是個變數。您的年齡隨著時間在變化,就像任何其他變數那樣。也就是說,變數的第一個特性是它會隨著時間而發生變化。另一個示例:您五歲時多高?很可能比現在矮得多。身高又是一個變數示例。但有一個很重要的區別點。注意,年齡是用整數來算的。身高一般要算到小數位(“浮點數”)。年齡:20 歲,30 歲。身高:1.8米,1.9米。這是個非常重要的特點:每個變數都屬於特定的型別。我們來看看還有哪些其他型別的變數。您可以用數字來描述很多引數,但怎麼描述文字呢?特殊字串型別就用於這個用途。此類變數型別僅包含行。現在我們來看看如何用 MQL4 語言建立和描述變數。示例:
int age = 25;
這裡我們看到一個整型變數 (int - integer)。Int 是 MQL4 語言裡的一個關鍵字,即我們使用一個整數型別。然後我們寫入“年齡”- 這是變數的名稱,即此變數中儲存的用於表達意義的詞。之後我們使用符號“=”將值 25 分配給此變數。每條指令之後都應有一個“;”。注意,任何變數的宣告和初始化都遵循以下形式:
[ 變數型別] [ 變數名稱] = [ 變數值];
此外,不必將值分配給變數(初始化),你可以這麼寫:
int age;
再舉一個例子:
double height = 1.95;
這裡我們宣告一個名為“身高”的變數,此變數儲存 double 型別值(浮點數、小數),並用“=”運算子分配值 1.95。
現在我們來看看字串變數:
string name = "Janet";
字串是一種變數型別,名稱是一個變數名稱,“Janet”是一個變數值。注意,字串型別變數的值要放在雙引號(“”)中間。
還有一種非常有用的變數型別 - 布林型。這種變數僅可接受兩個值:true 或 false。示例:
bool trend = false;
現在您應該記住一些簡單的東西。MQL4 語言是一種區分大小寫的語言,即用編寫程式碼時用大寫還是小寫字母有很大的區別。例如,如果您宣告幾個變數時使用相同的名稱但不同的大小寫,那將得到完全不同的變數:
double HIGHTPRICE; double hightprice; double HightPrice; double hightPrice;
上述程式碼將建立四個完全不同的變數。還請注意,MQL4 語言的所有關鍵字都是小寫的。
下一個示例:
DOUBLE hightPrice1; Double hightPrice2;
上述程式碼無法正常工作,因為“double”將不會被接受為 MQL4 語言的一個關鍵字。還有個更重要的注意事項,變數名稱不能用數字或特殊符號(*、&、%、$)開頭。例如:
double 1price; double %price;
註釋也是一個語言元素。如果在一行開頭寫入“//”,那麼整行都是註釋。這意味著編譯期間,這行將被忽略。例如:
// this is a comment
現在您可以看到,一個空指令碼程式碼包括對一個資料性字元的很多註釋。註釋您的程式碼。有時它會幫助您節省大量時間。
使用變數
現在我們來看看在宣告這些變數後該對它們做什麼。來一個簡單的例子:
double a = 50.0;// declare a value with a floating point and // assign the value 50 to it double b = 2.0; double c; c = a + b; // assign to the variable c sum of variables // a and b. Now the value is equal to 52. Like after // any other instruction put a semicolon (“;”) c = a - b; // diminution, c = 48 c = a*b; // multiplication, c = 100 c = a / b; // division, c = 25 c = (a + b)*a; // place the operations that should be performed // first inside the brackets. In our case // first we get the sum of a and b // after that this sum will be multiplied by a and assigned to c c = (a + b) / (a - b); // if there are several operations in brackets, // they will be performed c = a + b*3.0; // according to mathematic rules first you will get // multiplication b and 3, and then the sum
如果需要用某個變數執行一項運算,並分配一個結果給它,例如加 5,可以採用以下方式之一:
int a = 5; a = a + 5; // add 5 a += 5; // analogous a = a*5; a *= 5; // multiply a by 5 and assign to it a /= 5; // divide and assign
如要加 1 或減 1,用以下方法:
int a = 5; a++; // add1, it is called increment а--; // subtract 1, it is decrement
這都可以,但用這種指令碼的話,您無法確定這一切是否能正常執行,因為螢幕上沒有任何反應。
這就是顯示結果會很方便的原因。為此,我們需要使用一個整合函式 MessageBox()。
MessageBox()
一個函式就是一套指令,它接受引數,並根據引數顯示結果。在我們的示例中,MessageBox() 函式接受兩個引數:第一個是訊息文字,第二個是標題文字。示例如下:
MessageBox("Hello, World! There is some text.","caption");
要執行一個函式,首先寫入其名稱。別忘了區分大小寫!然後在括號中寫入引數,用逗號隔開。我們示例中的引數是字串型別的引數。正如我們記得的那樣,所有行都用引號(“”)括起來的。在任何指令的末尾加一個分號。為了正確理解,我們來看圖。它顯示了程式碼和結果之間的關聯。
當然,一切正常。但我們如何展示其他型別的變數呢?很簡單 - 牢記在心裡:
int a = 50; int b = 100; MessageBox("It is very simple. a+b=" + (a + b), "a+b=?")
得到的結果是:
如您所料,MQL4 就是這麼設計的,當我們嘗試向某行中新增其他數字型別時,它會自動將數字傳遞到行中併合並它們。這真是一個美妙的特性!您也可以對字串變數進行這種運算:
int a = 50; int b = 100; string str1 = "a + b ="; str1 += a + b; // now str1 = "a + b = 150" // now use the variable str1 as // a first parameter MessageBox(str1, "a + b = ?");
現在您知道如何使用 MessageBox() 函式提取不同的資料了。但是,能夠顯示簡單的數學運算結果又算什麼?我們對 MQL4 的要求可不僅僅是算個加法和乘法,不是嗎?
陣列
別怕。這很簡單。看一看。假設您要記住五個價格。我們該怎麼做?好吧,我們這麼做:
double price1 = 1.2341; double price2 = 1.2321; double price3 = 1.2361; double price4 = 1.2411; double price5 = 1.2301;
我們得到五個變數,它們只有一個數據型別,且描述同一個引數 - 價格。我們可以換種方法,用一個數組。一個數組就是一組變數,指數不同,但名稱相同。從五個元素宣告一個數組,方式如下:
double price[5];
常用形式:
(陣列型別)(陣列名稱) [元素數量];
在我們的示例中:陣列型別 - double(雙型別),名稱 - price(價格),元素數量 - 5。我們來看如何引用這些陣列元素:
double price[5]; // declare an array of 5 elements price[0] = 1.2341; // refer to the first element of the array and // assign a price to it. Note // that the index of the first element starts with 0 // It is an important feature, // you should get used to it. price[1] = 1.2321; // refer to the second element price[2] = 1.2361; // and so on price[3] = 1.2411; price[4] = 1.2301;
就像常用變數一樣,我們可以對陣列元素執行任何運算。實際上,陣列的元素就是常用變數。
double price[2]; price[0] = 1.2234; price[1] = 1.2421; MessageBox("Middle price is " + (price[0] + price[1]) / 2.0,"middle price");
宣告一個數組時,可以向所有元素分配初始值。
double price[2] = {1.2234, 1.2421};
我們簡單地列舉元素的初始值(在大括號中用逗號隔開)。在這種情況下,您可讓編譯器自動放上元素的數量,而不是您手動寫入。
double price[] = {1.2234, 1.2421};
毫無疑問這些都是可以的,不過,遺憾的是,這根本沒什麼用處。我們總得弄到一點實際的資料吧!例如,當前價格、時間、可用金額等。
整合或內建的陣列和變數
沒有實際的資料,我們當然什麼都做不了。要獲得實際資料,我們只需參考對應的內建陣列。以下是幾個內建陣列:
High[0]; // refer to the last maximal price, // that the bar has achieved in the current timeframe // and current currency pair. Currency pair and // the timeframe depend on the chart, on which you // have started a script. It is very important to remember! Low[0]; // minimal price of the last bar // in the current chart. Volume[0]; // value of the last bar in the current chart.
要正確理解內建陣列和指數,看看這個:
最後一根條柱的指數(編號)為 0,旁邊一根為 1,以此類推。
還有內建常用變數。例如,Bars 顯示當前圖表中的條柱數量。它是個常用變數,但它早就已經聲明瞭,並非在您的指令碼中進行的宣告。此變數像其他內建陣列和變數一樣始終存在。
迴圈
假設您決定要計算圖表中所有條柱的最大價格的平均值。為此,您將各個元素輪流新增到一個變數,如下所示:
double AveragePrice = 0.0; AveragePrice += High[0]; AveragePrice += High[1]; AveragePrice += High[2]; AveragePrice += High[3]; AveragePrice += High[4]; // ... and so on AveragePrice /= Bars;
我只能告訴您一點:這種方法可行,但有些可笑。迴圈專門適用此類用途。注意,所有運算都是完全類似的,只有指數從 0 更改為變數 Bars-1 值。確定計數器並用其引用陣列元素某種程度上來說就已經非常方便了。我們可以用迴圈來解決這個任務:
double AveragePrice = 0.0; for(int a = 0; a < Bars; a++) { AveragePrice += High[a]; }
我們看看各行:
double AveragePrice = 0.0; // everything is clear // this is a cycle. or(int a = 0; a < Bars; a++)
迴圈用關鍵字 for 開頭。(還有其他型別的迴圈,例如while,但我們現在不討論它們)。然後在引號中指明用分號隔開的計數器、迴圈計算條件、計數器增加運算。通常它以以下方式呈現:
for(declaration of a counter; the cycle operation conditions; counter changes) { // the source code, that will be repeated is in braces, }
讓我們更近距離地瞭解迴圈宣告的各個階段。
計數宣告int 型別用於此計數器。變數計數器的名稱無關緊要。您應初始化主值,例如初始化為 0。
計數器計算條件:這很簡單。在此處確定一個條件,如果它為 true,迴圈繼續進行。否則,迴圈終止。例如在我們的示例中:
a < Bars
很明顯,當變數計數器小於變數 Bars 時,迴圈將繼續進行。假設變數 Bars=10,則在迴圈上每移動一次,變數增加 1,直至達到 10。之後,迴圈將停止。
計數器更改:如果我們不更改計數器(在我們的示例中是增加它),將發生什麼情況?迴圈將永不停止,因為條件永不會滿足。為了更好地理解迴圈的意義,我編寫了一段可執行迴圈的程式碼,並提供了註釋:
// the cycle: // double AveragePrice=0.0; // // for(int a=0;a> // { // AveragePrice+=High[a]; // } // // will be performed in this way: // double AveragePrice=0.0; int a=0; AveragePrice+=High[a]; a++; // now a=1, suppose Bars=3. // then the cycle goes on, because Bars > a AveragePrice+=High[a]; a++; // a=2 AveragePrice+=High[a]; а++; // a=3 // the conditions is not fulfilled any more, so the cycle // stops, because a=3 and Bars=3
現在您應該瞭解迴圈的工作方式了。但還應該再瞭解一些細節。
迴圈計算條件各有不同。如下例中所示:
a>10 // the cycle works while a>10 a!=10 // the cycle works while a is not equal to 10 a==20 // while a is not equal to 20 a>=2 // while a is more or equal to 2 a<=30 // while a is less or equal to 30
計數器可用不同的方式進行更改。例如,您不必每次都加 1。您可以這麼做:
a-- // the counter will each time decrease by 1 a += 2 // the counter will each time increase by 2
此外,您可將計數器更改放到迴圈主體內。如下例中所示:
for(int a=0; a<Bars;) { AveragePrice+=High[a]; a++; // the counter changes inside the cycle body } >
也不必在迴圈中宣告變數計數器。您可以換一種方式:
int a = 0; for(;a < Bars;) { AveragePrice += High[a]; a++; // the counter changes inside the cycle body }
如果迴圈主體僅包含一個操作符,如下所示:
for(int a = 0; a < Bars; a++) { AveragePrice += High[a]; }
然後也不必使用發括號:
for(int a = 0; a < Bars; a++) AveragePrice += High[a];
這就是目前為止有關迴圈的所有內容了。還有其他的迴圈型別,我們會在下一課中討論。現在您應該知道何時使用迴圈並記住語法。嘗試編寫幾個迴圈,以通過 MessageBox() 函式顯示計數器值。嘗試編寫一個非連續迴圈,看看啟動後會發生什麼。
條件
還有一個您始終會用到的重要專案 - 條件。我們的生活充滿著大量的條件以及根據這些條件進行的活動。我們往往採用的是條件式的思考方式。例如:“如果我有充足的時間,我會讀這本書。如果沒有,還是讀本雜誌吧”。您可以生成數以百計的此類條件和行動。但我們如何用 MQL4 來編寫它們呢?示例如下:
// of course the conditionsn should be written in MQL4 if( I have enough time ) { // here we place any actions, directions in MQL4 will read this book; } // if the first condition is not fulfilled, // the second is fulfilled else { read a magazine; // code }
現在您應可理解這種條件式語法了。我們看看用 MQL4 語言完整編寫的條件:
int a = 10; int b = 0; if(a > 10 ) { b = 1; } else { b = 2; } MessageBox("b=" + b,".");
這一切都很簡單。完成後,b 的值是多少?當然 b=2,因為條件 a > 10 並未滿足。這很簡單。另外也不必使用其他關鍵字:
int a = 10; int b = 0; if(a > 10) { b = 1; }
在這種情況下,如果某個條件未滿足,遵循大括號中該條件的程式碼塊將被忽略。在我們的示例中是在滿足 b = 0 之後。同時還要注意條件的構建方式。我們知道,不同型別的變數會獲得不同的值,例如:
- int - 整數(1、60、772);
- double - 浮點數(1.0021、0.221);
- string - 僅行(“字”、“一些文字”);
- bool - 僅 true 或 false(true、false)。
因此,得出的結論是:在條件中比較僅帶可接受值的變數,例如:
int Integer=10; double Double=1.0; string String="JustWord"; bool Bool=true; if(Integer<10) // the condition is correct { MessageBox("It works!","Really!"); } if(Double!=1.0) // the condition is correct { MessageBox("works!","Simple!"); } if(String==10) // this is nonsense!! // we found the variable //String with string type, but 10 is int { MessageBox("Wrong type","u can't c this"); } if(String!="Word") // ok {{ // ... } if(Bool==true) // correct { // ... }
注意,我們使用條件運算子(==, !=, >, <, >=, <=).對於字串型別和布林型別,僅使用 == 和 != 進行比較。
現在我們來了解一下其中內容的含義。是的,您可以在迴圈中使用條件,也可以在條件中使用迴圈;您可以在條件中使用其他條件,等等。例如:
int a=0; double b=0.0; bool e; if(a==0) { for(int c=0;c<Bars;c++) { b+=High[c]; } if(b>500.0) { e=true; } else { e=false; } }
下例顯示的是條件的另一種使用方式:
int a=0; int result; if(a==0) { result=1; } else if(a==1) { result=2; } else if(a==2) { result=3; } else { result=4; }
如果某個條件預設有另一個條件,在關鍵字“else”後編寫該條件,具體參考上述編碼。這也是可行的。其他條件的數量不受限制。如果用於滿足條件的行動符合一項運算,您可忽略迴圈中的大括號。
if(a==1) { b=2; } // or this way: if(a==1) b=2;
複雜條件
通常一個條件是不夠的。您需要比較很多引數;這時就需要使用複雜條件。例如,如果我有足夠的時間和耐心,我會好好學習 MQL4 語言。我們可以將它編寫成程式碼:
if((enough time) && (enough oatience))
{
I will learn MQL4 language;
}
這意味著您首先應將複雜條件細分為簡單條件,將它們放到括號中,並在它們之間加上 &&(邏輯 AND)或 ||(邏輯 OR)。如果兩個條件都為真,新增 && (AND)。如果只有一個條件為真,新增 || (OR)。示例如下:
nt a=10; int b=20; if((a>5) && (b<50)) MessageBox("Its works!","Yes");
除此以外,您可根據需要任意新增和組合條件:
int a=10; int b=20; if ( ((a>5) || (a<15)) && ( b==20)) MessageBox("It works, too!","Yes");
混合使用
要在迴圈中同時使用複雜條件和簡單條件,您可能要編寫一段非常複雜的程式碼。幾乎所有機制都可以用 MQL4 語言的這些淺顯結構來表示。如果理解了這些簡單程式碼的編寫和操作原理,您也就弄懂了一半的 MQL4 或任何其他程式語言!這其實是非常簡單的!您所需要的只是多練習。試著儘可能多地編寫指令碼,以記住語法和獲取實踐經驗。此外,檢視附件 examples.mq4 中的示例,嘗試理解它們。
其他內建變數和陣列
您已瞭解了 High[]、Low[]、Volume[] 等陣列以及 Bars 這個變數。以下是一些其他的有用變數:
double Open[] // the array of prices of the current // chart opening bars double Close[] // the array of prices of the current // chart closing bars double Bid // the last known buying price in // the current currency pair double Ask // the last known selling price in // the current currency pair
總結
您已經學了不少東西。也許現在您腦子裡亂糟糟一團。重讀本文,加深記憶,進行練習,嘗試理解含義。我敢保證,不用多久一切都將會豁然開朗。本文介紹了整個 MQL4 語言的基礎知識。對文中內容理解地越深,後續的學習就越輕鬆。再多說一句 - 後續的學習為何為簡單得多?因為本文的內容就已經是最難的部分了。下一篇文章中,我們將學習 MQL4 語言的各個不同特點,並瞭解其他一些整合函式,這些函式將為程式設計帶來更多的可能性。