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

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

這篇不談策略,只做三件事:把環境裝好、寫一支不會下單只會印字的 EA、看到它真的跑起來。

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 就有幾個亂碼資料夾,之後找不到檔案先來這裡翻。

打開 MetaEditor

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

MetaEditor 視窗:左邊導航是 MQL5 資料夾的檔案樹,中間編輯區開著 HelloWorld.mq5,下方工具箱的「錯誤」頁顯示 0 errors, 0 warnings。
MetaEditor:①導航 ②編輯區 ③工具箱(按 F7 編譯後的「錯誤」頁)

用嚮導建立第一個 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_BID 就是 Bid 價。Ask 是買進時的價、Bid 是賣出時的價,兩者的差就是點差。點差會變動,我的帳戶上 EURUSD 有時是 0,Ask 和 Bid 就一樣。

_Symbol、_Period、_Digits 這幾個底線開頭的是 MT5 幫你準備好的預定義變數,分別是商品名稱、週期、小數位數。

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

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

編譯

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

HelloWorld.mq5
code generated
0 errors, 0 warnings, 1336 ms elapsed, cpu='AVX2 + FMA3'

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

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

掛到圖表上

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

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

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

Hello World! EA 啟動:EURUSD PERIOD_H1
HelloWorld 掛在 EURUSD H1 圖表上:左邊導航列出 HelloWorld,右上角有 EA 名稱和帽子圖示,左上角 Comment 顯示 Tick 數 19 和 Ask、Bid、時間,下方「專家」頁是 OnInit 印的啟動訊息。
①導航的 HelloWorld ②名稱與帽子 ③Comment ④「專家」頁日誌

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

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

  1. MT5 按 Ctrl+R 打開「策略測試」。
  2. EA 選 HelloWorld,商品 EURUSD,週期 H1。「日期」下拉先選「自定義週期」,再在右邊兩格填起迄:2025.01.02 到 2025.01.03。模式選「每次報價」。
  3. 按「開始」,幾秒就跑完。切到「日誌」頁看輸出。

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

2025.01.02 00:00:00   Hello World! EA 啟動:EURUSD PERIOD_H1
2025.01.02 00:19:00   Tick #100  Ask=1.03603  Bid=1.03510
2025.01.02 00:39:25   Tick #200  Ask=1.03563  Bid=1.03547
2025.01.02 00:56:28   Tick #300  Ask=1.03576  Bid=1.03560
...(中間略)
2025.01.02 23:52:00   Tick #103800  Ask=1.02669  Bid=1.02668
2025.01.02 23:56:49   Tick #103900  Ask=1.02678  Bid=1.02677
2025.01.02 23:59:59   EA 結束,原因代碼 = 1,共收到 103991 個 tick

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

OnDeinit 的原因代碼

上面測試器結束時印出「原因代碼 = 1」。初學會遇到的幾個:

  • 1 REASON_REMOVE:被從圖表移除(測試結束也算這個)
  • 2 REASON_RECOMPILE:重新編譯了,MT5 會自動重新載入
  • 5 REASON_PARAMETERS:使用者改了輸入參數
  • 8 REASON_INITFAILED:OnInit 沒有回傳 INIT_SUCCEEDED

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

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

發佈留言

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

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