1. 程式人生 > >面向初學者的 MQL4 語言系列之1——MQL4 語言入門

面向初學者的 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 語言的各個不同特點,並瞭解其他一些整合函式,這些函式將為程式設計帶來更多的可能性。