MQL5 基本語法入門:從變數到函數的完整指南

📌 本文重點
深入學習 MQL5 核心語法:資料型別、變數宣告、運算子、條件判斷、迴圈、函數定義與常用內建函數。無論你是程式新手或有其他語言背景,本文都能讓你快速掌握 MQL5 語法基礎。

前言:MQL5 是什麼語言?

MQL5(MetaQuotes Language 5)是 MetaTrader 5 平台的原生程式語言,語法結構與 C++ 非常相似。如果你有 C/C++/C# 或 Java 的基礎,上手 MQL5 會非常快;即使是程式新手,只要掌握本文介紹的核心語法,也能開始撰寫自己的 EA(Expert Advisor,專家顧問)。

MQL5 程式主要分為三類:

  • Expert Advisor (EA):自動交易機器人,在 OnTick() 中執行交易邏輯
  • Custom Indicator(自訂指標):繪製技術分析線,在 OnCalculate() 中計算數值
  • Script(腳本):一次性執行的程式,在 OnStart() 中完成任務

第一章:資料型別(Data Types)

MQL5 是強型別語言,每個變數在宣告時必須指定型別。以下是最常用的型別:

型別 大小 範圍 / 說明 典型用途
int 4 bytes -2,147,483,648 ~ 2,147,483,647 訂單 ID、計數器、週期
long 8 bytes ±9.2 × 10¹⁸ 大整數、Position Ticket
double 8 bytes 15-16 位有效數字 價格、止損、手數
bool 1 byte true / false 條件旗標、開關
string 可變 Unicode 文字 品種名稱、日誌訊息
datetime 8 bytes 1970年起的秒數 K 線時間、交易時間
color 4 bytes RGB 顏色值 指標線條顏色

第二章:變數宣告與初始化

// ===== 基本變數宣告 =====

// 整數 - 用於訂單編號、魔術數字
int magicNumber = 12345;
int barCount    = 0;

// 浮點數 - 用於所有價格相關計算
double entryPrice  = 1.08500;
double stopLoss    = 1.08000;
double takeProfit  = 1.09500;
double lotSize     = 0.10;

// 布林值 - 條件旗標
bool isLongSignal  = false;
bool isInitialized = true;

// 字串
string symbolName = "EURUSD";
string comment    = "MA Cross Strategy";

// 日期時間
datetime lastBarTime = 0;        // 初始化為 1970-01-01
datetime currentTime = TimeCurrent(); // 取得目前時間

// ===== 常數宣告(值不可修改)=====
const int    MAX_POSITIONS = 3;
const double RISK_PERCENT  = 2.0;

// ===== 輸入參數(可在 EA 設定介面調整)=====
input int    InpFastPeriod = 10;   // 快線週期
input int    InpSlowPeriod = 30;   // 慢線週期
input double InpLotSize    = 0.1;  // 交易手數
input bool   InpUseFilter  = true; // 啟用過濾器

第三章:運算子(Operators)

// ===== 算術運算子 =====
double a = 10.0, b = 3.0;
double sum       = a + b;   // 13.0
double diff      = a - b;   // 7.0
double product   = a * b;   // 30.0
double quotient  = a / b;   // 3.333...
int    remainder = 10 % 3;  // 1(取餘數,只適用整數)

// 自增 / 自減
int counter = 0;
counter++;   // counter = 1
counter--;   // counter = 0
counter += 5; // counter = 5
counter -= 2; // counter = 3
counter *= 2; // counter = 6

// ===== 比較運算子(回傳 bool)=====
bool isEqual    = (a == b);  // false
bool isNotEqual = (a != b);  // true
bool isGreater  = (a > b);   // true
bool isLess     = (a < b);   // false
bool isGteq     = (a >= b);  // true
bool isLteq     = (a <= b);  // false

// ===== 邏輯運算子 =====
bool condition1 = true;
bool condition2 = false;

bool andResult = condition1 && condition2; // false(兩者都要 true)
bool orResult  = condition1 || condition2; // true(只要一個 true)
bool notResult = !condition1;              // false(反轉)

// 實際應用:多條件交易信號
bool isBuySignal = (fastMA > slowMA) && (rsi < 70) && !hasPosition;

第四章:條件判斷(If/Else/Switch)

// ===== 基本 if/else =====
double profit = PositionGetDouble(POSITION_PROFIT);

if (profit >= 100.0)
{
    Print("獲利超過 $100,考慮獲利了結");
    ClosePosition();
}
else if (profit <= -50.0)
{
    Print("虧損超過 $50,觸發止損");
    ClosePosition();
}
else
{
    Print("部位進行中,當前盈虧: $", profit);
}

// ===== Switch(適合多個固定值的判斷)=====
int signal = GetSignal(); // 假設回傳 1=買, -1=賣, 0=無信號

switch (signal)
{
    case 1:
        OpenBuy();
        break;
    case -1:
        OpenSell();
        break;
    case 0:
    default:
        // 無動作
        break;
}

// ===== 三元運算子(簡化的 if/else)=====
string direction = (signal == 1) ? "BUY" : (signal == -1) ? "SELL" : "NONE";
Print("信號方向: ", direction);

第五章:迴圈(Loops)

// ===== For 迴圈 - 最常用,適合已知次數的迭代 =====

// 計算最近20根K線的平均收盤價
double sum = 0;
int period = 20;
for (int i = 0; i < period; i++)
{
    sum += iClose(_Symbol, _Period, i);
}
double average = sum / period;
Print("20期平均收盤價: ", average);

// ===== 遍歷所有持倉(常用模式)=====
int totalPositions = PositionsTotal();
for (int i = totalPositions - 1; i >= 0; i--)  // 從後往前遍歷,避免刪除時索引錯亂
{
    string posSymbol = PositionGetSymbol(i);
    if (posSymbol == _Symbol)
    {
        long magic = PositionGetInteger(POSITION_MAGIC);
        Print("持倉 #", i, " | Magic: ", magic, " | 品種: ", posSymbol);
    }
}

// ===== While 迴圈 - 條件未知時使用 =====
int retries = 0;
int maxRetries = 3;
bool success = false;

while (retries < maxRetries && !success)
{
    success = TrySendOrder();
    if (!success)
    {
        Print("下單失敗,重試 ", retries + 1, "/", maxRetries);
        Sleep(1000); // 等待 1 秒後重試
        retries++;
    }
}

// ===== Break 和 Continue =====
for (int i = 0; i < 100; i++)
{
    if (i == 10) break;    // 當 i=10 時跳出迴圈
    if (i % 2 == 0) continue; // 跳過偶數,繼續下一次迭代
    Print("奇數: ", i);
}

第六章:函數定義與呼叫

// ===== 基本函數語法 =====
// 格式:返回型別 函數名稱(參數型別 參數名稱, ...)

// 無返回值(void)函數
void LogTradeInfo(string action, double price, double lots)
{
    Print("[", TimeToString(TimeCurrent()), "] ",
          action, " | 價格: ", DoubleToString(price, Digits()),
          " | 手數: ", DoubleToString(lots, 2));
}

// 有返回值的函數
double CalculatePipValue(string symbol, double lots)
{
    double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE);
    double tickSize  = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
    double point     = SymbolInfoDouble(symbol, SYMBOL_POINT);
    return lots * tickValue * (tickSize / point);
}

// 布林型函數(常用於檢查條件)
bool IsNewBar()
{
    static datetime lastBarTime = 0;
    datetime currentBarTime = iTime(_Symbol, _Period, 0);
    
    if (currentBarTime != lastBarTime)
    {
        lastBarTime = currentBarTime;
        return true;  // 新K線出現
    }
    return false;
}

// 使用預設參數值
double NormalizeLots(double lots, string symbol = NULL)
{
    if (symbol == NULL) symbol = _Symbol;
    double minLot  = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
    double maxLot  = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
    double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
    
    lots = MathMax(lots, minLot);
    lots = MathMin(lots, maxLot);
    lots = MathRound(lots / lotStep) * lotStep;
    return NormalizeDouble(lots, 2);
}

// ===== 在 OnTick() 中呼叫函數 =====
void OnTick()
{
    if (!IsNewBar()) return;
    
    double pv = CalculatePipValue(_Symbol, 0.1);
    Print("每點價值: $", DoubleToString(pv, 4));
}

第七章:陣列(Arrays)

// ===== 靜態陣列 =====
double prices[5] = {1.0800, 1.0810, 1.0795, 1.0820, 1.0815};
Print("第一個價格: ", prices[0]); // 1.0800(索引從0開始)

// ===== 動態陣列 =====
double maBuffer[];  // 宣告動態陣列(空的)
ArrayResize(maBuffer, 100);  // 調整大小為100個元素
ArraySetAsSeries(maBuffer, true); // 設為時間序列(索引0=最新數據)

// ===== 使用 CopyBuffer 填充指標數據 =====
int maHandle = iMA(_Symbol, _Period, 20, 0, MODE_SMA, PRICE_CLOSE);
double maValues[3];
ArraySetAsSeries(maValues, true);

if (CopyBuffer(maHandle, 0, 0, 3, maValues) == 3)
{
    Print("當前MA: ", maValues[0]);   // 最新K線的MA值
    Print("前一根MA: ", maValues[1]); // 前一根K線的MA值
    Print("前兩根MA: ", maValues[2]); // 前兩根K線的MA值
}

第八章:常用內建函數速查

// ===== 帳戶資訊 =====
double balance     = AccountInfoDouble(ACCOUNT_BALANCE);      // 帳戶餘額
double equity      = AccountInfoDouble(ACCOUNT_EQUITY);       // 淨值
double margin      = AccountInfoDouble(ACCOUNT_MARGIN);       // 已用保證金
double freeMargin  = AccountInfoDouble(ACCOUNT_FREEMARGIN);   // 可用保證金
long   leverage    = AccountInfoInteger(ACCOUNT_LEVERAGE);    // 槓桿倍數
string currency    = AccountInfoString(ACCOUNT_CURRENCY);     // 帳戶貨幣

// ===== 品種資訊 =====
double bid    = SymbolInfoDouble(_Symbol, SYMBOL_BID);        // 賣出價
double ask    = SymbolInfoDouble(_Symbol, SYMBOL_ASK);        // 買入價
double spread = SymbolInfoDouble(_Symbol, SYMBOL_SPREAD);     // 點差
double point  = SymbolInfoDouble(_Symbol, SYMBOL_POINT);      // 最小變動單位
int    digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); // 小數位數

// ===== K 線數據 =====
double openPrice  = iOpen(_Symbol, _Period, 0);   // 當前K線開盤價
double highPrice  = iHigh(_Symbol, _Period, 0);   // 最高價
double lowPrice   = iLow(_Symbol, _Period, 0);    // 最低價
double closePrice = iClose(_Symbol, _Period, 0);  // 收盤價(即時更新)
datetime barTime  = iTime(_Symbol, _Period, 0);   // K線時間
long   barVolume  = iVolume(_Symbol, _Period, 0); // 成交量

// ===== 數學函數 =====
double absVal = MathAbs(-1.5);       // 1.5(絕對值)
double maxVal = MathMax(1.5, 2.3);   // 2.3(取較大值)
double minVal = MathMin(1.5, 2.3);   // 1.5(取較小值)
double sqrtVal = MathSqrt(9.0);      // 3.0(平方根)
double floorVal = MathFloor(3.7);    // 3.0(向下取整)
double roundVal = MathRound(3.5);    // 4.0(四捨五入)

// ===== 字串函數 =====
string upper = StringToUpper("eurusd");       // "EURUSD"
int    len   = StringLen("Hello MQL5");       // 10
string sub   = StringSubstr("EURUSD", 0, 3); // "EUR"
string str   = DoubleToString(1.23456, 2);   // "1.23"
string strI  = IntegerToString(12345);        // "12345"
double val   = StringToDouble("1.0850");      // 1.0850

// ===== 時間函數 =====
datetime now    = TimeCurrent();              // 伺服器目前時間(UTC)
datetime local  = TimeLocal();               // 本機時間
string   strTime = TimeToString(now, TIME_DATE|TIME_MINUTES); // "2026.03.11 10:30"

總結:MQL5 語法核心要點

  1. 強型別:每個變數都有明確型別,double 用於價格,int 用於計數
  2. 分號結尾:每條陳述式必須以 ; 結尾
  3. 大括號:用 { } 包住程式碼區塊
  4. input 參數:讓用戶在不修改程式碼的情況下調整 EA 設定
  5. 陣列從0開始array[0] 是第一個元素;設為時間序列後,[0] 是最新數據
  6. 函數要在使用前宣告或定義:或在檔案尾端定義,頂部宣告原型

延伸學習


本文由 James Lee 撰寫,轉載請註明出處。內容僅供教育目的,不構成投資建議。

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *