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

迴圈:有效率地掃描 K 線

for 與 while,加上兩個讓迴圈不會把終端機卡住的防護。

初學閱讀時間約 8 分鐘初學 → 進階第 07 / 17 堂
在 MetaEditor 實際跑一次
掃描最近的 K 線,找出區間與連續性

存成 MQL5/Scripts/Lesson7Loops.mq5。它複製最近的 K 線、找出最高價與最低價,然後用 while 迴圈數出一段連續同向 K 線的長度。

//+------------------------------------------------------------------+
//| Lesson 7 - Loops: range scan and streak count                    |
//+------------------------------------------------------------------+
#property copyright "Strategist Academy"
#property version   "1.00"

void OnStart()
{
   int lookback = 20;

   MqlRates rates[];
   ArraySetAsSeries(rates, true);          // index 0 = newest bar

   int copied = CopyRates(_Symbol, _Period, 0, lookback + 1, rates);
   if(copied < lookback + 1)
   {
      Print("CopyRates returned ", copied, " bars - expected ", lookback + 1,
            ". Error: ", GetLastError());
      return;
   }

   // Start at 1: bar 0 is still forming, so it is not a completed range.
   double highest = rates[1].high;
   double lowest  = rates[1].low;
   int    highBar = 1;
   int    lowBar  = 1;

   for(int i = 2; i <= lookback && !IsStopped(); i++)
   {
      if(rates[i].high > highest) { highest = rates[i].high; highBar = i; }
      if(rates[i].low  < lowest)  { lowest  = rates[i].low;  lowBar  = i; }
   }

   Print("Range over last ", lookback, " completed bars on ", _Symbol);
   Print("Highest high: ", DoubleToString(highest, _Digits), "  (", highBar, " bars ago)");
   Print("Lowest low:   ", DoubleToString(lowest, _Digits), "  (", lowBar, " bars ago)");
   Print("Range size:   ", DoubleToString((highest - lowest) / _Point, 1), " points");

   // while loop: how many consecutive completed closes sit above the midpoint?
   double mid    = (highest + lowest) / 2.0;
   int    streak = 0;
   int    i      = 1;

   while(i <= lookback && rates[i].close > mid)
   {
      streak++;
      i++;
   }

   Print("Consecutive closes above midpoint: ", streak, " of ", lookback);
}
如何執行
  1. 1. 從 MT5 開啟 MetaEditor(按 F4), 選擇這支程式該放的資料夾——ExpertsIndicators Scripts
  2. 2. 開新檔案、把這段程式貼上去,然後按 F7 編譯。Errors 分頁顯示的錯誤 都修掉。
  3. 3. 回到 MT5,把它拖到圖表上——如果是 EA,就打開 Strategy Tester

for 是你的預設

當你知道要迭代幾次時——掃描最近 20 根 K 線、走過 50 個商品——用 for。模式永遠一樣:初始化一個計數器、測試它、遞增。

次數未知時用 while

當你一直迴圈到某個條件改變時用 while:往回走直到收盤價跌破某個價位、重試一個操作直到成功或撞到上限。永遠要保證那個條件有可能變成 false,否則你就寫了一個會凍結圖表的無窮迴圈。

兩個永遠不該跳過的防護

  • !IsStopped()——讓終端機在使用者移除程式或關閉時能中止你的迴圈。少了它,一個長迴圈可以讓 MT5 完全沒反應。
  • 邊界檢查——永遠不要索引超過 rates_total,或超過你複製進去的那個陣列的大小。如果複製回來的 K 線比你要求的少,就提前回傳。

序列順序 vs. 最舊在前,再一次

當你用 CopyRates 複製到自己的陣列時,順序由 ArraySetAsSeries(arr, true) 決定。設了它,索引 0 就是最新的那根 K 線,對「幾根 K 線之前」這種邏輯讀起來很自然。這堂課的掃描使用序列順序——刻意與第 4 堂課不同的慣例,讓你兩種都習慣,並學會先確認自己現在在哪一種裡。

差一根(off-by-one)

這種形狀的程式碼最常見的 bug,就是少掃或多掃一根 K 線。如果你想要最近 20 根已完成 K 線的最高價,把第 0 根排除——它還在形成中。

你剛完成了什麼

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