一、为什么运算符在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;
}
```
十、运算符最佳实践清单
参考来源:
9. 下一步
第8篇将讲解MQL4条件判断语句(if/else/switch) – 使用if、else if、else和switch语句控制EA交易逻辑流程的完整指南,附带实际交易示例。