返回《給 CFD 交易者的 MetaTrader 5 與 MQL5》
第一部分

資料型別、變數與嚴格型別

MQL5 不會像 Pine 那樣默默幫你轉型。你必須分清楚 int 與 double。

初學閱讀時間約 8 分鐘初學 → 進階第 03 / 17 堂
在 MetaEditor 實際跑一次
型別、轉型與浮點等值陷阱

存成 MQL5/Scripts/Lesson3Types.mq5 然後執行。注意最後兩行:天真地比較 double 會失敗,用容許誤差比較才會成功。

//+------------------------------------------------------------------+
//| Lesson 3 - Types, conversions, float comparison                  |
//+------------------------------------------------------------------+
#property copyright "Strategist Academy"
#property version   "1.00"

void OnStart()
{
   string   sym      = _Symbol;
   int      bars     = Bars(sym, _Period);
   double   point    = _Point;
   datetime now      = TimeCurrent();
   long     tradeMode= SymbolInfoInteger(sym, SYMBOL_TRADE_MODE);
   bool     tradable = (tradeMode != SYMBOL_TRADE_MODE_DISABLED &&
                        tradeMode != SYMBOL_TRADE_MODE_CLOSEONLY);

   Print("Symbol:        ", sym);
   Print("Bars on chart: ", bars);
   Print("Point:         ", DoubleToString(point, _Digits));
   Print("Server time:   ", TimeToString(now, TIME_DATE | TIME_SECONDS));
   Print("Trading open:  ", tradable ? "yes" : "no");

   // Build strings explicitly - no implicit double-to-string here.
   string label = StringFormat("%s | bars=%d | point=%.5f", sym, bars, point);
   Print(label);

   // Parsing back from string
   string volText = "0.10";
   double vol     = StringToDouble(volText);
   Print("Parsed volume: ", DoubleToString(vol, 2));

   // --- The float trap ------------------------------------------------
   double a = 0.1 + 0.2;
   Print("0.1 + 0.2 == 0.3 exactly? ", (a == 0.3) ? "true" : "false  <-- the trap");
   Print("Same check with tolerance: ",
         (MathAbs(a - 0.3) < 0.000001) ? "true" : "false");

   // In trading terms: compare prices using points, not raw equality.
   double bid  = SymbolInfoDouble(sym, SYMBOL_BID);
   double level= NormalizeDouble(bid, _Digits);
   Print("Bid equals its own normalised copy (within half a point)? ",
         (MathAbs(bid - level) <= _Point / 2.0) ? "yes" : "no");
}
如何執行
  1. 1. 從 MT5 開啟 MetaEditor(按 F4), 選擇這支程式該放的資料夾——ExpertsIndicators Scripts
  2. 2. 開新檔案、把這段程式貼上去,然後按 F7 編譯。Errors 分頁顯示的錯誤 都修掉。
  3. 3. 回到 MT5,把它拖到圖表上——如果是 EA,就打開 Strategy Tester

MQL5 是嚴格型別的

這是從 PineScript 過來最大的一個調整。在 Pine 裡,一個值是一個 series,runtime 多半會原諒你。在 MQL5 裡你宣告一個型別,編譯器就會要求你遵守它。型別不合是編譯錯誤,不是默默算錯——這在一開始很惱人,但長期來說真的比較安全。

你實際上會用到的型別

  • int——計數、位移、錯誤碼、magic number(用 longulong)。
  • double——所有價格、成交量與金額。
  • bool——由 &&||! 產生的旗標。
  • string——商品名稱、註解、訊息。
  • datetime——從 1970 年起的秒數。用 TimeToString 格式化。
  • color——clrDodgerBlue,或 C'255,0,0'
  • ENUM_*——具名常數:ENUM_TIMEFRAMESENUM_ORDER_TYPEENUM_MA_METHOD,還有數十個其他。優先用這些,不要用魔術數字。

轉型是明確的

DoubleToString()IntegerToString()StringToDouble()StringToTime()StringFormat()。不要倚賴隱含轉型——也永遠不要把一個 double 串進字串然後期待它長得對。

永遠不要用等值比較兩個 double

浮點運算代表 0.1 + 0.2 並不精確等於 0.3。任何你在比較兩個價格的地方,都要用一個以 point 為單位的容許誤差。這在「價格有沒有碰到我的價位」這類檢查上咬得最兇——精確比較會永遠靜默地不觸發。

作用域與 static

在函式內宣告的變數,在函式回傳時就消失。宣告在檔案作用域的,則活到程式結束。把一個區域變數標成 static 可以在多次呼叫之間保留它的值——這是一個不必用全域變數就能數 tick 或記住上一根 K 線的便宜做法。

你剛完成了什麼

給 CFD 交易者的 MetaTrader 5 與 MQL5》的第 03 / 17 堂課。跑完範例或讀完這段之後, 把它勾起來,然後進下一堂課。