在 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. 從 MT5 開啟 MetaEditor(按 F4), 選擇這支程式該放的資料夾——Experts、Indicators 或 Scripts。
- 2. 開新檔案、把這段程式貼上去,然後按 F7 編譯。Errors 分頁顯示的錯誤 都修掉。
- 3. 回到 MT5,把它拖到圖表上——如果是 EA,就打開 Strategy Tester。
MQL5 是嚴格型別的
這是從 PineScript 過來最大的一個調整。在 Pine 裡,一個值是一個 series,runtime 多半會原諒你。在 MQL5 裡你宣告一個型別,編譯器就會要求你遵守它。型別不合是編譯錯誤,不是默默算錯——這在一開始很惱人,但長期來說真的比較安全。
你實際上會用到的型別
int——計數、位移、錯誤碼、magic number(用 long/ulong)。
double——所有價格、成交量與金額。
bool——由 &&、||、! 產生的旗標。
string——商品名稱、註解、訊息。
datetime——從 1970 年起的秒數。用 TimeToString 格式化。
color——clrDodgerBlue,或 C'255,0,0'。
ENUM_*——具名常數:ENUM_TIMEFRAMES、ENUM_ORDER_TYPE、ENUM_MA_METHOD,還有數十個其他。優先用這些,不要用魔術數字。
轉型是明確的
用 DoubleToString()、IntegerToString()、StringToDouble()、StringToTime() 與 StringFormat()。不要倚賴隱含轉型——也永遠不要把一個 double 串進字串然後期待它長得對。
永遠不要用等值比較兩個 double
浮點運算代表 0.1 + 0.2 並不精確等於 0.3。任何你在比較兩個價格的地方,都要用一個以 point 為單位的容許誤差。這在「價格有沒有碰到我的價位」這類檢查上咬得最兇——精確比較會永遠靜默地不觸發。
作用域與 static
在函式內宣告的變數,在函式回傳時就消失。宣告在檔案作用域的,則活到程式結束。把一個區域變數標成 static 可以在多次呼叫之間保留它的值——這是一個不必用全域變數就能數 tick 或記住上一根 K 線的便宜做法。