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

陣列、結構與物件

MqlRates、MqlTradeRequest、動態陣列,以及剛好夠讓你讀得懂標準函式庫的物件導向。

中級閱讀時間約 10 分鐘初學 → 進階第 09 / 17 堂
在 MetaEditor 實際跑一次
MqlRates、一個自訂 struct 與動態陣列

存成 MQL5/Scripts/Lesson9Structures.mq5。它把 K 線複製進一個 struct 陣列、建立一個自訂 struct,並設定動態陣列的大小——後面每一個 EA 背後的模式。

//+------------------------------------------------------------------+
//| Lesson 9 - MqlRates, custom structs, dynamic arrays              |
//+------------------------------------------------------------------+
#property copyright "Strategist Academy"
#property version   "1.00"

// A tiny value object - MQL5 lets you group related fields like this.
struct Level
{
   double price;
   string label;
   bool   isSupport;
};

void OnStart()
{
   int bars = 50;

   // --- MqlRates: one struct per bar ---------------------------------
   MqlRates rates[];
   ArraySetAsSeries(rates, true);            // 0 = newest

   int copied = CopyRates(_Symbol, _Period, 0, bars, rates);
   if(copied != bars)
   {
      Print("CopyRates returned ", copied, " of ", bars, ". Error: ", GetLastError());
      return;
   }

   double hi = rates[1].high;
   double lo = rates[1].low;                 // bar 0 is still forming
   for(int i = 2; i < bars && !IsStopped(); i++)
   {
      hi = MathMax(hi, rates[i].high);
      lo = MathMin(lo, rates[i].low);
   }

   Print("Newest completed bar close: ", DoubleToString(rates[1].close, _Digits));
   Print("Bar time: ", TimeToString(rates[1].time, TIME_DATE | TIME_MINUTES));

   // --- Custom struct -------------------------------------------------
   Level levels[2];
   levels[0].price     = hi;
   levels[0].label     = "50-bar high";
   levels[0].isSupport = false;
   levels[1].price     = lo;
   levels[1].label     = "50-bar low";
   levels[1].isSupport = true;

   for(int i = 0; i < 2; i++)
      Print(levels[i].label, ": ", DoubleToString(levels[i].price, _Digits),
            "   support=", levels[i].isSupport ? "yes" : "no");

   // --- Dynamic array -------------------------------------------------
   double closes[];
   ArrayResize(closes, bars);
   for(int i = 0; i < bars; i++)
      closes[i] = rates[i].close;

   Print("closes[0] (newest) = ", DoubleToString(closes[0], _Digits));
   Print("closes[", bars - 1, "] (oldest) = ", DoubleToString(closes[bars - 1], _Digits));
   Print("Series order set on rates? ", ArrayGetAsSeries(rates) ? "yes" : "no");
}
如何執行
  1. 1. 從 MT5 開啟 MetaEditor(按 F4), 選擇這支程式該放的資料夾——ExpertsIndicators Scripts
  2. 2. 開新檔案、把這段程式貼上去,然後按 F7 編譯。Errors 分頁顯示的錯誤 都修掉。
  3. 3. 回到 MT5,把它拖到圖表上——如果是 EA,就打開 Strategy Tester

你會一直遇到的結構

MQL5 內建一組 struct,它們是這套 API 的通用貨幣。學會這五個,大多數文件就會變得可讀:

  • MqlRates——一根 K 線:time, open, high, low, close, tick_volume, spread, real_volume
  • MqlTick——一個 tick:bid, ask, last, volume, time_msc, flags
  • MqlTradeRequest——你想送出的那張單。
  • MqlTradeResult——伺服器實際做了什麼。
  • MqlDateTime——拆開來的行事曆時間。

你也可以用 struct 宣告自己的——像這堂課那樣,把一個價格跟一個標籤綁在一起就很方便。

動態陣列與 ArrayResize

double arr[]; 宣告一個空陣列,再用 ArrayResize(arr, n) 設定大小。許多 API 函式會幫你調整大小——CopyRates 會——但如果你是自己在組一個,先 resize。

ArraySetAsSeries 決定你的索引方式

如果你要索引 0 是最新那根 K 線,在複製之前呼叫它。複製之後才呼叫,那你已經用另一種順序把陣列填滿了。搞錯這個會產生一個看起來能跑、但數值被位移或反轉的指標——當數字看起來怪時,先檢查這裡。

類別,簡短講

MQL5 支援類別:privatepublic 區段、建構子、解構子、繼承。你不需要寫一個才能有生產力,但你必須讀得懂它們,因為整個標準函式庫(CTradeCPositionInfoCSymbolInfo)都是類別架構。實例化、呼叫方法、往下走。

字串是物件,不是字元陣列

與 C 不同,MQL5 的字串自己管理記憶體。用 + 串接,用 ==StringCompare 比較,不用煩惱 buffer。

你剛完成了什麼

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