Summary: 本文全面讲解MQL4语言中的所有运算符类型,包括算术运算符、比较运算符、逻辑运算符、赋值运算符和三元运算符,通过实际EA代码示例演示运算符优先级和表达式求值规则。




一、为什么运算符在EA开发中如此重要

运算符是告诉编译器执行特定数学、关系或逻辑操作的符号。理解运算符对于创建交易条件、计算仓位大小和控制EA逻辑流程至关重要。

二、MQL4完整运算符速查表

| 类别 | 运算符 | 用途说明 | 代码示例 |
|------|--------|----------|----------|
| 算术运算符 | + - * / % | 基础数学计算 | lotSize * price |
| 赋值运算符 | = += -= *= /= %= | 变量赋值操作 | total += 1 |
| 比较运算符 | == != > < >= <= | 数值比较判断 | price > maValue |
| 逻辑运算符 | && || ! | 布尔逻辑组合 | trendUp && rsiLow |
| 位运算符 | & | ^ ~ << >> | 二进制操作(进阶) | flags | mask |
| 三元运算符 | ? : | 条件赋值 | isBuy ? 1 : -1 |

三、算术运算符 - 基础数学计算

算术运算符对数值(int和double类型)执行数学计算。

```mql4
// EA计算中的算术运算符
double entryPrice = 1.09250;
double stopLoss = entryPrice - 0.0010; // 减法:1.09150
double takeProfit = entryPrice + 0.0020; // 加法:1.09450
double riskAmount = AccountBalance() * 0.02; // 乘法:2%风险
double lotSize = riskAmount / 1000; // 除法
int remainder = 10 % 3; // 取模:1(10除以3的余数)

// 实用EA示例 - 仓位大小计算器
double CalculatePositionSize(double riskPercent, double stopLossPoints) {
double accountEquity = AccountBalance();
double riskDollars = accountEquity * (riskPercent / 100);
double pointValue = MarketInfo(Symbol(), MODE_TICKVALUE);
double calculatedSize = riskDollars / (stopLossPoints * pointValue);

// 应用最小/最大限制和步长舍入
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
double stepSize = MarketInfo(Symbol(), MODE_LOTSTEP);

calculatedSize = MathFloor(calculatedSize / stepSize) * stepSize;
calculatedSize = MathMax(minLot, MathMin(maxLot, calculatedSize));

return NormalizeDouble(calculatedSize, 2);
}

// 使用算术运算符计算动态移动止损
double CalculateTrailingStop(double currentPrice, double entryPrice, int trailingPoints) {
double profitPoints = (currentPrice - entryPrice) / Point();
if(profitPoints > trailingPoints) {
return currentPrice - (trailingPoints * Point());
}
return 0;
}
```

四、赋值运算符 - 变量赋值操作

赋值运算符将值存储到变量中。简单赋值(=)最常用,复合赋值运算符将运算与赋值结合。

```mql4
// 基础赋值
int totalOrders = 0; // 初始化计数器
double currentProfit = 0; // 初始化利润变量
string symbolName = "EURUSD"; // 初始化字符串

// 复合赋值运算符
int orderCount = 5;
orderCount += 3; // 等同于:orderCount = orderCount + 3(结果:8)
orderCount -= 2; // 等同于:orderCount = orderCount - 2(结果:6)
orderCount *= 2; // 等同于:orderCount = orderCount * 2(结果:12)
orderCount /= 3; // 等同于:orderCount = orderCount / 3(结果:4)
orderCount %= 3; // 等同于:orderCount = orderCount % 3(结果:1)

// 实用EA示例 - 使用复合赋值的交易计数器
int g_buyTrades = 0;
int g_sellTrades = 0;
int g_totalTrades = 0;

void UpdateTradeCounters(int orderType) {
if(orderType == OP_BUY) {
g_buyTrades++; // 买入计数器自增
} else if(orderType == OP_SELL) {
g_sellTrades++; // 卖出计数器自增
}
g_totalTrades = g_buyTrades + g_sellTrades;
}

// 使用赋值运算符的风险管理
double g_dailyLoss = 0;
double g_maxDailyLoss = 1000;

void TrackDailyLoss(double lossAmount) {
g_dailyLoss += lossAmount; // 累加到每日亏损总额
if(g_dailyLoss >= g_maxDailyLoss) {
Print("每日亏损限额已达,关闭所有持仓");
CloseAllPositions();
}
}
```

五、比较运算符 - 交易条件测试

比较运算符比较两个值并返回true或false。它们是所有交易决策的基础。

```mql4
// 交易条件中的比较运算符
double currentPrice = Bid;
double maValue = iMA(NULL, 0, 20, 0, MODE_SMA, PRICE_CLOSE, 1);
double rsiValue = iRSI(NULL, 0, 14, PRICE_CLOSE, 1);

// 等于和不等于
if(currentPrice == maValue) { } // 等于(外汇中很少出现)
if(currentPrice != maValue) { } // 不等于
if(rsiValue > 70) { } // 大于(超买)
if(rsiValue < 30) { } // 小于(超卖)
if(currentPrice >= maValue + 10*Point()) { } // 大于或等于
if(currentPrice <= maValue - 10*Point()) { } // 小于或等于

// 实用EA示例 - 多条件交易信号生成
bool GenerateBuySignal() {
double maFast = iMA(NULL, 0, 10, 0, MODE_SMA, PRICE_CLOSE, 1);
double maSlow = iMA(NULL, 0, 30, 0, MODE_SMA, PRICE_CLOSE, 1);
double rsi = iRSI(NULL, 0, 14, PRICE_CLOSE, 1);
double close1 = iClose(NULL, 0, 1);
double close2 = iClose(NULL, 0, 2);

bool trendUp = maFast > maSlow;
bool oversold = rsi < 30;
bool bullishCandle = close1 > close2;

// 组合比较条件生成信号
if(trendUp == true && oversold == true && bullishCandle == true) {
return true;
}
return false;
}

// 止损距离有效性验证
bool IsStopLossValid(double stopLossPrice, int orderType) {
double currentPrice = (orderType == OP_BUY) ? Ask : Bid;
double minDistance = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point();

if(orderType == OP_BUY) {
return (currentPrice - stopLossPrice) >= minDistance;
} else {
return (stopLossPrice - currentPrice) >= minDistance;
}
}
```

六、逻辑运算符 - 组合交易条件

逻辑运算符将多个布尔表达式组合起来创建复杂的交易规则。

```mql4
// 逻辑运算符:&&(与)、||(或)、!(非)

// 与运算符(&&)- 所有条件都必须为真
if(trendUp && rsiOversold && noPosition) {
OpenBuyOrder(); // 仅当三个条件全部为真时执行
}

// 或运算符(||)- 至少一个条件必须为真
if(priceAboveUpperBand || priceBelowLowerBand) {
Alert("价格触及布林带边界");
}

// 非运算符(!)- 反转布尔值
if(!IsTradeAllowed()) {
Print("交易功能未开启");
return;
}

// 实用EA示例 - 综合信号验证
bool ValidateTradeSignal(int signalType) {
// 使用逻辑运算符检查多个条件
bool timeOk = IsTradingHours();
bool spreadOk = MarketInfo(Symbol(), MODE_SPREAD) < 30;
bool noExistingTrade = CountOrders(magicNumber) == 0;
bool balanceOk = AccountBalance() > 1000;
bool newsOk = !IsNewsTime(); // 非运算符示例

// 组合所有条件
if(timeOk && spreadOk && noExistingTrade && balanceOk && newsOk) {
if(signalType == SIGNAL_BUY) {
bool buyConditions = CheckBuyConditions();
return buyConditions;
} else if(signalType == SIGNAL_SELL) {
bool sellConditions = CheckSellConditions();
return sellConditions;
}
}
return false;
}

// 混合运算符的复杂入场逻辑
void CheckEntryConditions() {
double maFast = iMA(NULL, 0, 10, 0, MODE_SMA, PRICE_CLOSE, 1);
double maSlow = iMA(NULL, 0, 30, 0, MODE_SMA, PRICE_CLOSE, 1);
double rsi = iRSI(NULL, 0, 14, PRICE_CLOSE, 1);

bool buySignal = (maFast > maSlow) && (rsi < 30);
bool sellSignal = (maFast < maSlow) && (rsi > 70);
bool reversalSignal = (rsi < 25) || (rsi > 75);

if(buySignal && !HasBuyPosition()) {
OpenBuy();
} else if(sellSignal && !HasSellPosition()) {
OpenSell();
} else if(reversalSignal && !HasAnyPosition()) {
Print("RSI达到极端值 - 监控反转机会");
}
}
```

七、三元运算符(?:)- 条件赋值

三元运算符提供了一种紧凑的if-else赋值方式。

```mql4
// 语法:条件 ? 条件为真时的值 : 条件为假时的值

// 基础三元运算符用法
int direction = (maFast > maSlow) ? 1 : -1; // 1表示买入,-1表示卖出
double lotSize = (accountBalance > 10000) ? 0.1 : 0.05;
string signal = (rsi < 30) ? "买入" : "等待";

// 实用EA示例 - 动态参数选择
double GetDynamicStopLoss() {
double volatility = iATR(NULL, 0, 14, 1);
double baseStop = 50 * Point();

// 使用三元运算符进行波动率调整
return (volatility > 0.0020) ? baseStop * 2 : baseStop;
}

// 使用三元运算符确定入场价格
double GetEntryPrice(int orderType) {
return (orderType == OP_BUY) ? Ask : Bid;
}

// 订单类型转字符串
string OrderTypeToString(int orderType) {
return (orderType == OP_BUY) ? "买入" :
(orderType == OP_SELL) ? "卖出" :
(orderType == OP_BUYLIMIT) ? "买入限价" :
(orderType == OP_SELLLIMIT) ? "卖出限价" : "未知";
}

// 基于风险的手数计算(多条件三元)
double GetRiskLotSize(double riskPercent) {
double balance = AccountBalance();
double riskAmount = balance * riskPercent / 100;
double baseLot = riskAmount / 10000;

// 嵌套三元运算符(谨慎使用,可能降低可读性)
double lotSize = (balance > 50000) ? baseLot * 1.5 :
(balance > 20000) ? baseLot * 1.2 :
(balance > 5000) ? baseLot : baseLot * 0.5;

return NormalizeDouble(lotSize, 2);
}
```

八、运算符优先级 - 哪个运算先执行

运算符优先级决定了复杂表达式中运算的执行顺序。

```mql4
// 运算符优先级表(从高到低)
// 1. () 括号
// 2. ! - +(一元运算符)
// 3. * / %
// 4. + -
// 5. < > <= >=
// 6. == !=
// 7. &&
// 8. ||
// 9. = += -=(赋值运算符)

// 优先级示例
double result = 5 + 3 * 2; // 乘法优先:5 + 6 = 11
double result2 = (5 + 3) * 2; // 括号优先:8 * 2 = 16

bool condition = a > b && c < d || e == f;
// 求值顺序为:((a > b) && (c < d)) || (e == f)

// 实用EA示例 - 正确的优先级使用
bool GenerateSignal() {
double maFast = iMA(NULL, 0, 10, 0, MODE_SMA, PRICE_CLOSE, 1);
double maSlow = iMA(NULL, 0, 30, 0, MODE_SMA, PRICE_CLOSE, 1);
double rsi = iRSI(NULL, 0, 14, PRICE_CLOSE, 1);
int totalOrders = CountOrders(magicNumber);

// 不使用括号 - 意图不明确
// bool buy = maFast > maSlow && rsi < 30 || totalOrders == 0;

// 使用括号 - 清晰且正确
bool buy = (maFast > maSlow) && (rsi < 30) && (totalOrders == 0);
bool sell = (maFast < maSlow) && (rsi > 70) && (totalOrders == 0);

return buy || sell;
}

// 涉及优先级的复杂计算
double CalculateRiskRewardRatio() {
double entry = 1.09250;
double stopLoss = 1.09150;
double takeProfit = 1.09450;

// 不加括号时除法优先于减法
double ratio = (takeProfit - entry) / (entry - stopLoss);

return NormalizeDouble(ratio, 2);
}
```

九、完整EA模板(使用所有运算符类型)

```mql4
//+------------------------------------------------------------------+
//| OperatorsEA.mq4|
//+------------------------------------------------------------------+
#property copyright "Copyright 2024"
#property version "1.00"
#property strict

input double InpLotSize = 0.1;
input int InpMagic = 12345;
input int InpRiskPercent = 2;
input int InpMaxDailyLoss = 500;

double g_dailyLoss = 0;
int g_todayTrades = 0;
datetime g_lastReset = 0;

//+------------------------------------------------------------------+
//| EA初始化函数 |
//+------------------------------------------------------------------+
int OnInit() {
g_lastReset = GetMidnight();
Print("EA已初始化,风险管理已启用");
return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| EA主执行函数 |
//+------------------------------------------------------------------+
void OnTick() {
static datetime lastBarTime = 0;
if(Time[0] == lastBarTime) return;
lastBarTime = Time[0];

ResetDailyIfNeeded();

if(IsTradeAllowed() && !IsMaxDailyLossReached()) {
EvaluateAndTrade();
}
}

//+------------------------------------------------------------------+
//| 重置每日计数器 |
//+------------------------------------------------------------------+
void ResetDailyIfNeeded() {
datetime midnight = GetMidnight();
if(midnight != g_lastReset) {
g_dailyLoss = 0;
g_todayTrades = 0;
g_lastReset = midnight;
Print("每日计数器已重置");
}
}

//+------------------------------------------------------------------+
//| 使用运算符的主交易逻辑 |
//+------------------------------------------------------------------+
void EvaluateAndTrade() {
double maFast = iMA(NULL, 0, 10, 0, MODE_SMA, PRICE_CLOSE, 1);
double maSlow = iMA(NULL, 0, 30, 0, MODE_SMA, PRICE_CLOSE, 1);
double rsi = iRSI(NULL, 0, 14, PRICE_CLOSE, 1);
int orderCount = CountOrders(InpMagic);

// 复合赋值和比较运算符
bool trendUp = maFast > maSlow;
bool trendDown = maFast < maSlow;
bool oversold = rsi < 30;
bool overbought = rsi > 70;
bool canTrade = (orderCount == 0) && (g_todayTrades < 5);

// 逻辑运算符组合条件
if(trendUp && oversold && canTrade) {
double dynamicLot = CalculateLotSize(InpRiskPercent, 50);
OpenOrder(OP_BUY, dynamicLot);
g_todayTrades++; // 自增运算符
}
else if(trendDown && overbought && canTrade) {
double dynamicLot = CalculateLotSize(InpRiskPercent, 50);
OpenOrder(OP_SELL, dynamicLot);
g_todayTrades++;
}
}

//+------------------------------------------------------------------+
//| 使用算术运算符计算手数 |
//+------------------------------------------------------------------+
double CalculateLotSize(int riskPercent, int stopPoints) {
double riskAmount = AccountBalance() * (riskPercent / 100.0);
double pointValue = MarketInfo(Symbol(), MODE_TICKVALUE);
double rawLot = riskAmount / (stopPoints * pointValue);

double stepSize = MarketInfo(Symbol(), MODE_LOTSTEP);
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);

// 复合赋值和三元运算符
rawLot = MathFloor(rawLot / stepSize) * stepSize;
rawLot = (rawLot < minLot) ? minLot : (rawLot > maxLot) ? maxLot : rawLot;

return NormalizeDouble(rawLot, 2);
}

//+------------------------------------------------------------------+
//| 检查是否达到每日亏损限额 |
//+------------------------------------------------------------------+
bool IsMaxDailyLossReached() {
return g_dailyLoss >= InpMaxDailyLoss;
}
```

十、运算符最佳实践清单

  • [ ] 使用括号使复杂表达式易于阅读

  • [ ] 避免嵌套三元运算符(改用if-else语句)

  • [ ] 对计数器和累加器使用复合赋值(+=、-=)

  • [ ] 混合使用&&和||运算符时必须使用括号

  • [ ] 比较浮点数时要格外小心(使用NormalizeDouble)

  • [ ] 价格差异比较时使用Point()函数

  • [ ] 尽量使用正向逻辑(!false)而非负向逻辑


  • 参考来源:

  • MetaQuotes Ltd.《MQL4官方文档 - 运算符》(2024)

  • Elder, Alexander.《以交易为生》(1993)

  • 王伟.《MQL4编程实战指南》(2022)


  • 9. 下一步

    第8篇将讲解MQL4条件判断语句(if/else/switch) – 使用if、else if、else和switch语句控制EA交易逻辑流程的完整指南,附带实际交易示例。