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

條件邏輯與運算子

if/else、switch,以及那個在券商擋你之前就先擋掉壞單的下單前檢查。

初學閱讀時間約 7 分鐘初學 → 進階第 06 / 17 堂
在 MetaEditor 實際跑一次
用真實的券商限制做一個下單前檢查

存成 MQL5/Scripts/Lesson6PreTradeGate.mq5。在幾個不同商品上、不同時段執行它——光是價差檢查就會改變答案。

//+------------------------------------------------------------------+
//| Lesson 6 - Pre-trade validation gate                             |
//+------------------------------------------------------------------+
#property copyright "Strategist Academy"
#property version   "1.00"

void OnStart()
{
   string sym   = _Symbol;
   double ask   = SymbolInfoDouble(sym, SYMBOL_ASK);
   double bid   = SymbolInfoDouble(sym, SYMBOL_BID);
   double point = _Point;

   long   stopsLevel = SymbolInfoInteger(sym, SYMBOL_TRADE_STOPS_LEVEL);
   long   tradeMode  = SymbolInfoInteger(sym, SYMBOL_TRADE_MODE);

   double spreadPoints = (ask - bid) / point;
   double stopPts      = 200;          // candidate stop distance in points
   double maxSpread    = 20;           // our own tolerance

   bool spreadOk = (spreadPoints <= maxSpread);
   bool stopOk   = (stopPts >= (double)stopsLevel);
   bool modeOk   = (tradeMode == SYMBOL_TRADE_MODE_FULL);

   Print("Symbol:        ", sym);
   Print("Spread:        ", DoubleToString(spreadPoints, 1), " points (limit ", maxSpread, ")  ok=", spreadOk ? "YES" : "NO");
   Print("Stop distance: ", DoubleToString(stopPts, 0), " points (broker min ", stopsLevel, ")  ok=", stopOk ? "YES" : "NO");
   Print("Trade mode:    ", EnumToString((ENUM_SYMBOL_TRADE_MODE)tradeMode), "  ok=", modeOk ? "YES" : "NO");

   if(spreadOk && stopOk && modeOk)
      Print("RESULT: all pre-trade checks passed - safe to send.");
   else if(!modeOk)
      Print("RESULT: symbol is not fully tradable right now (session or broker restriction).");
   else if(!spreadOk)
      Print("RESULT: spread too wide - skip this entry, it is not worth the cost.");
   else
      Print("RESULT: stop too close - the broker would reject this with invalid stops.");

   // --- float comparison ----------------------------------------------
   double a = 0.1 + 0.2;
   Print("");
   Print("0.1 + 0.2 == 0.3 ?        ", (a == 0.3) ? "true" : "false   <-- never compare doubles");
   Print("with 1e-6 tolerance:      ", (MathAbs(a - 0.3) < 0.000001) ? "true" : "false");
}
如何執行
  1. 1. 從 MT5 開啟 MetaEditor(按 F4), 選擇這支程式該放的資料夾——ExpertsIndicators Scripts
  2. 2. 開新檔案、把這段程式貼上去,然後按 F7 編譯。Errors 分頁顯示的錯誤 都修掉。
  3. 3. 回到 MT5,把它拖到圖表上——如果是 EA,就打開 Strategy Tester

一個交易條件的形狀

每一條進場規則都是一個布林運算式。在 MQL5 裡,你用比較運算子(><>=<===!=)加上 &&(且)、||(或)把它們組合起來,並用 ! 否定。大量使用括號——一個條件裡的優先順序 bug 是看不見的,直到那個 EA 在不該交易的時候交易。

用 switch 處理列舉

當你在一個 enum 上分支時——訂單類型、交易模式、圖表事件——switch 比一串 else if 更好讀,而且編譯器可以警告你漏掉的 case。

送出之前先檢查

在 Pine 裡你可以丟出一張單,然後讓回測引擎去收拾。在 MQL5 裡,一張被拒絕的單是一個真實事件,帶著真實的回傳碼。養成在呼叫交易函式之前就驗證的習慣:

  • 這個商品與這個帳戶現在可以交易嗎?
  • 價差可以接受嗎?
  • 我的停損距離至少有 SYMBOL_TRADE_STOPS_LEVEL 個 point 嗎?
  • 可用保證金夠嗎?

在本地端沒通過這些檢查是免費的。在券商那邊沒通過,代價是一整頁的 retcode 紀錄,更糟的是一支默默一個禮拜什麼都不做的程式。

再一次:浮點比較規則

比較價格要用以 point 為單位的容許誤差,永遠不要用 ==。這堂課的腳本會明確把那個差異印出來,讓你親眼看見。

你剛完成了什麼

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