MT5 開發環境設定與第一個程式

MT4 那一系列寫完之後停了好幾年,中間 MT5 已經變成主流,我自己也早就整個搬到 MT5 上了。所以重新開一個系列,這次用 MT5 跟 MQL5,從零開始,目標是自己寫出能跑的 EA(Expert Advisor,自動交易程式)。

第一篇不談策略,只做三件事:把環境裝好、寫一支不會下單只會印字的 EA、看到它真的跑起來。這樣後面每篇才有東西可以動手。

  • MT5、MetaEditor、MQL5 分別是什麼
  • 找到 MQL5 資料夾,知道檔案該放哪裡
  • 用精靈建立 EA,補上程式碼,編譯成 .ex5
  • 掛到圖表上看輸出;沒報價的時候改用策略測試器看

MT5、MetaEditor、MQL5 是什麼

MetaTrader 5(MT5)是交易平台本身,看圖、下單都在這裡。MetaEditor是寫程式的編輯器兼編譯器,裝 MT5 就會一起裝好,不用另外找。MQL5是在 MetaEditor 裡面寫的語言,長得很像 C++,寫過任何一種 C 系語言看到會覺得眼熟;完全沒寫過也沒關係,這系列會從變數、判斷、迴圈慢慢來,跟以前 MT4 系列一樣。

MQL5 能寫三種程式,先知道差別就好:

種類放的資料夾什麼時候執行
EA(EA 交易)Experts掛在圖表上,每來一個報價執行一次,可以下單
指標(Indicator)Indicators掛在圖表上,負責算數字畫線,不能下單
腳本(Script)Scripts拖上圖表執行一次就結束,例如一鍵平倉

安裝 MT5 並登入模擬帳號

到券商網站下載 MT5 安裝檔就好,我用的是 Tickmill。不同券商的 MT5 程式本體都一樣,差別只在能交易的商品跟點差。裝完先登入一個模擬帳號,開模擬帳號的流程跟以前 MT4 那篇 差不多,只是伺服器要選 MT5 的 Demo。

第一次開發強烈建議用模擬帳號。這篇的程式不會下單,但之後的會,寫錯一行就是真的錢。

找到 MQL5 資料夾

MT5 的程式碼、編譯結果、設定檔全部放在「資料資料夾」底下的 MQL5。在 MT5 主選單點「檔案 → 打開數據文件夾」(快速鍵 Ctrl+Shift+D)就會用檔案總管打開,不用自己猜路徑。

MQL5\
├─ Experts\      EA(自動交易程式)放這裡  ← 這系列主要在這
├─ Indicators\   自訂技術指標
├─ Scripts\      腳本:跑一次就結束的小工具
├─ Include\      .mqh 標頭檔,可重複使用的程式碼
├─ Libraries\    編譯好的函式庫
├─ Files\        程式讀寫檔案只能在這個沙盒裡
├─ Images\       圖片資源
└─ Profiles\     圖表範本(templates)、測試器參數(Tester)

補充一個路徑的小知識,之後找不到檔案的時候會用到:

  • 一般安裝:資料資料夾在 C:\Users\你的帳號\AppData\Roaming\MetaQuotes\Terminal\一串亂碼\,裝了幾個券商的 MT5 就有幾個亂碼資料夾。
  • 可攜模式(portable):用 terminal64.exe /portable 啟動,資料資料夾就在安裝目錄裡面。我自己都用這個模式,MQL5 就在 MT5 旁邊,備份跟找檔案都方便。

打開 MetaEditor

在 MT5 按 F4,或主選單「工具 → MetaQuotes 語言編輯器」。MetaEditor 的畫面分三塊:左邊「導航」是 MQL5 資料夾的檔案樹,中間是編輯區,下面「工具箱」會顯示編譯結果跟錯誤訊息。

用精靈建立第一個 EA

  1. MetaEditor 點「檔案 → 新增」(Ctrl+N),會跳出 MQL 精靈。
  2. 選「EA交易 (模板)」,下一步。
  3. 名稱填 Experts\HelloWorld,作者、連結隨意,參數這篇用不到,下一步。
  4. 後面幾頁問要不要加事件處理函數,全部不勾,直接完成。

精靈會產生一份骨架,裡面就是三個函數:OnInit()OnDeinit()OnTick()。EA 的一生就是這三個函數:掛上去跑一次 OnInit,之後每個報價跑一次 OnTick,被拿掉的時候跑一次 OnDeinit。

程式碼

把精靈產生的內容整份換成下面這段,存檔(Ctrl+S)。註解跟字串裡有中文沒關係,這篇的範例就是這樣直接編譯過的。

//+------------------------------------------------------------------+
//|                                                   HelloWorld.mq5 |
//|                                     冏掉的Alan羅  orzalanluo.com |
//+------------------------------------------------------------------+
#property copyright "orzalanluo.com"
#property link      "https://orzalanluo.com"
#property version   "1.00"
#property description "MT5 教學 01:第一個 EA,只印訊息、不下單"

int g_TickCount = 0;   // 收到幾個 tick

//--- EA 掛上圖表時執行一次
int OnInit()
{
   Print("Hello World! EA 啟動:", _Symbol, " ",
         EnumToString(_Period));
   return INIT_SUCCEEDED;
}

//--- EA 被移除、換週期、關程式時執行一次
void OnDeinit(const int reason)
{
   Comment("");   // 清掉圖表左上角的文字
   Print("EA 結束,原因代碼 = ", reason,
         ",共收到 ", g_TickCount, " 個 tick");
}

//--- 每來一個報價(tick)就執行一次
void OnTick()
{
   g_TickCount++;
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

   // 圖表左上角即時顯示,不用開日誌也看得到
   Comment("Hello World!\n",
           "Tick 數:", g_TickCount, "\n",
           "Ask:", DoubleToString(ask, _Digits),
           "  Bid:", DoubleToString(bid, _Digits), "\n",
           "時間:", TimeToString(TimeCurrent(),
                                  TIME_DATE | TIME_SECONDS));

   // 每 100 個 tick 才寫一行日誌,避免洗版
   if(g_TickCount % 100 == 0)
      Print("Tick #", g_TickCount,
            "  Ask=", DoubleToString(ask, _Digits),
            "  Bid=", DoubleToString(bid, _Digits));
}
//+------------------------------------------------------------------+

逐段說明

#property 那幾行是程式的說明資訊,會顯示在 EA 的屬性視窗,跟執行邏輯無關。

g_TickCount 宣告在所有函數外面,是全域變數,EA 掛著的期間值會一直保留,所以能一直累加。我的習慣是全域變數加 g_ 前綴,一眼就知道它是誰。

OnInit() 只在 EA 載入時跑一次,適合做初始化。最後一定要回傳 INIT_SUCCEEDED,回傳別的值 MT5 會直接把 EA 卸掉。

OnDeinit(const int reason) 在 EA 被移除、換週期、關程式時跑一次,reason 會告訴你是哪一種,代碼表放在文末。這裡順手用 Comment("") 把圖表左上角的文字清掉,不然 EA 拿掉了字還留在那。

OnTick() 是主角,每來一個報價就執行一次。SymbolInfoDouble(_Symbol, SYMBOL_ASK) 拿目前圖表商品的 Ask 價,_Symbol_Period_Digits 這幾個底線開頭的是 MT5 幫你準備好的預定義變數,分別是商品名稱、週期、小數位數。

Comment() 會把文字寫在圖表左上角,即時更新,不用開日誌就看得到,除錯很好用。Print() 則是寫進「專家」日誌,可以留下紀錄。因為 EURUSD 一天有幾千個 tick,Print 每個 tick 都寫會洗版,所以用 % 100 每一百個才寫一行。

DoubleToString(ask, _Digits) 是把價格轉成固定小數位的字串。直接把 double 丟給 Print 也可以印,但有時會印出 1.0358600000000001 這種東西,轉一下比較好看。

編譯

在 MetaEditor 按 F7(或工具列的「編譯」)。下面工具箱的「錯誤」頁會顯示結果,看到 0 errors 就成功了:

'HelloWorld.mq5'	HelloWorld.mq5	1	1
code generated		1	1
0 errors, 0 warnings, 1345 msec elapsed

成功後同一個資料夾會多出 HelloWorld.ex5.mq5 是你寫的原始碼,.ex5 是編譯出來給 MT5 執行的檔案,MT5 只認 .ex5。改了程式碼一定要重新編譯,不然圖表上跑的還是舊的。

如果有錯誤,工具箱會列出行號跟訊息,雙擊那一行會直接跳到出錯的位置。初學最常見的是漏分號、大括號沒成對,還有打到全形的標點符號(,、;「」),在程式碼裡全形符號一律是錯的,只能出現在字串跟註解裡。

掛到圖表上

  1. 回到 MT5,開一張圖表,例如 EURUSD H1。
  2. Ctrl+N 打開「導航」視窗,展開「EA交易」,應該會看到 HelloWorld。沒看到就在導航按右鍵「刷新」。
  3. 把 HelloWorld 拖到圖表上(或雙擊),會跳出屬性視窗。「一般」頁勾選「允許演算法交易」,按確定。這篇的 EA 不下單其實不勾也會跑,但養成習慣,之後的 EA 不勾就不能交易。
  4. 工具列上的「演算法交易」按鈕(Ctrl+E)要是啟用(綠色)狀態,這是整個平台的總開關。

成功的話,圖表右上角會出現「HelloWorld」和一頂小帽子圖示,左上角開始跳 Comment 的文字,Tick 數會一直增加。帽子上如果有紅色叉叉,就是演算法交易沒開,回去檢查上面第 3、4 步。

日誌在下方「工具箱」(Ctrl+T)的「專家」頁,時間和來源(HelloWorld (EURUSD,H1))兩欄後面會看到這一行:

Hello World! EA 啟動:EURUSD PERIOD_H1

沒有報價怎麼辦:用策略測試器

如果你是週末看這篇,掛上去只會看到 OnInit 那一行,Tick 數永遠是 0,因為休市沒有報價,OnTick 根本不會被呼叫。這不是程式壞了。這時候可以用策略測試器拿歷史資料餵給 EA,也是之後回測策略一定會用到的工具:

  1. MT5 按 Ctrl+R 打開「策略測試」。
  2. EA 選 HelloWorld,商品 EURUSD,週期 H1,日期自己填 2025.01.02 到 2025.01.03,模式選「每個報價」。
  3. 按「開始」,幾秒就跑完。切到「日誌」頁看輸出。

我實際跑出來的結果是這樣,一天有 5706 個 tick:

2025.01.02 00:00:00   Hello World! EA 啟動:EURUSD PERIOD_H1
2025.01.02 00:33:30   Tick #100  Ask=1.03586  Bid=1.03546
2025.01.02 01:02:20   Tick #200  Ask=1.03516  Bid=1.03515
2025.01.02 01:27:20   Tick #300  Ask=1.03529  Bid=1.03527
...(中間略)
2025.01.02 23:33:20   Tick #5600  Ask=1.02632  Bid=1.02631
2025.01.02 23:58:20   Tick #5700  Ask=1.02678  Bid=1.02677
2025.01.02 23:59:59   EA 結束,原因代碼 = 1,共收到 5706 個 tick

這也剛好說明了為什麼 Print 要每一百個 tick 才寫一行。

OnDeinit 的原因代碼

上面測試器結束時印出「原因代碼 = 1」。常見的幾個:

代碼常數意思
0REASON_PROGRAM程式自己呼叫 ExpertRemove() 結束
1REASON_REMOVE被從圖表移除(測試結束也算這個)
2REASON_RECOMPILE重新編譯了,MT5 會自動重新載入
3REASON_CHARTCHANGE圖表換了商品或週期
4REASON_CHARTCLOSE圖表被關掉
5REASON_PARAMETERS使用者改了輸入參數
6REASON_ACCOUNT換了交易帳戶
8REASON_INITFAILEDOnInit 沒有回傳 INIT_SUCCEEDED
9REASON_CLOSEMT5 被關掉

其中 2 很實用:在 MetaEditor 按 F7 重新編譯,圖表上的 EA 會自動重跑一次 OnDeinit 再 OnInit,不用手動拿掉再掛回去。

練習

  1. 把 Print 的頻率改成每 500 個 tick 一行,重新編譯,觀察圖表上的 EA 有沒有自動重新載入。
  2. 在 Comment 裡多顯示一行點差:ask - bid,再試著換算成點數(提示:除以 _Point)。
  3. 把 EA 掛到 XAUUSD 跟 USDJPY 各一張圖,比較 _Digits 印出來的價格小數位有什麼不同。

下一篇

環境有了、程式跑得起來,下一篇開始講 MQL5 語法:變數與型態、input 參數、if 判斷、迴圈、陣列。寫過 MT4 系列的人會發現九成一樣,我會把差異特別標出來。

本篇的 HelloWorld.mq5 可以在這裡下載:HelloWorld.mq5,放到 MQL5\Experts\ 底下,在 MetaEditor 打開按 F7 就能用。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料