MetaTrader5中止损代码if语句报错问题求助
基于RSI的马丁格尔MT5策略止损逻辑报错求助
我写了一款基于RSI的马丁格尔策略MetaTrader5代码,想要实现30%比例的止损,但代码里CalculateStopLoss函数(对应原代码第143和153行附近)的止损相关逻辑报错。修改后反而出现更多错误,不确定是语法还是逻辑问题,求技术帮助。
原代码如下:
// Include the definition of OrderType and order types #include <Trade\Trade.mqh> //+------------------------------------------------------------------+ //| martin2.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property strict // Include the definition of SELECT_BY_POS #define SELECT_BY_POS 0 // Inputs input int RSIPeriod = 14; // RSI period input double OverboughtLevel = 70; // Overbought level input double OversoldLevel = 30; // Oversold level input double InitialLotSize = 0.01; // Initial lot size input double MartingaleMultiplier = 2.0; // Martingale multiplier input double StopLossPercentage = 30.0; // Stop loss percentage // Global variables int orderCount = 0; // Order counter //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { double rsi = iRSI(Symbol(), 0, RSIPeriod, 0); // Get current RSI value from bar 0 double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID); // Get current Bid price double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // Get current Ask price // Check if RSI is above the overbought level if (rsi > OverboughtLevel) { // Calculate lot size for this order double lotSize = CalculateLotSize(); // Structures for request and result of the operation MqlTradeRequest request; MqlTradeResult result; // Fill the sell request request.action = TRADE_ACTION_DEAL; request.symbol = Symbol(); request.volume = lotSize; request.type = ORDER_TYPE_SELL; request.price = currentBid; // Use current Bid price request.sl = CalculateStopLoss(currentBid); // Calculate stop loss using Bid price request.comment = "Martingale RSI"; request.type_time = ORDER_TIME_GTC; request.magic = 123456; request.deviation = 20; // Send the sell order if (OrderSend(request, result)) { orderCount++; // Increment order counter } else { Print("Error opening sell order: ", GetLastError()); } } // Check if RSI is below the oversold level if (rsi < OversoldLevel) { // Calculate lot size for this order double lotSize = CalculateLotSize(); // Structures for request and result of the operation MqlTradeRequest request; MqlTradeResult result; // Fill the buy request request.action = TRADE_ACTION_DEAL; request.symbol = Symbol(); request.volume = lotSize; request.type = ORDER_TYPE_BUY; request.price = currentAsk; // Use current Ask price request.sl = CalculateStopLoss(currentAsk); // Calculate stop loss using Ask price request.comment = "Martingale RSI"; request.type_time = ORDER_TIME_GTC; request.magic = 123456; request.deviation = 20; // Send the buy order if (OrderSend(request, result)) { orderCount++; // Increment order counter } else { Print("Error opening buy order: ", GetLastError()); } } } //+------------------------------------------------------------------+ //| Function to calculate lot size | //+------------------------------------------------------------------+ double CalculateLotSize() { double lotSize = InitialLotSize * MathPow(MartingaleMultiplier, orderCount); return lotSize; } //+------------------------------------------------------------------+ //| Function to calculate stop loss | //+------------------------------------------------------------------+ double CalculateStopLoss(double entryPrice) { double stopLossPrice; int totalOrders = OrdersTotal(); // Get total number of orders // Check if there are open orders if (totalOrders == 0) { Print("Error: No open orders."); return 0; } // Select the last order using the order number and selection mode if (!OrderSelect(totalOrders - 1, SELECT_BY_POS)) { Print("Error selecting order."); return 0; } // Calculate stop loss distance in points double stopLossDistance = entryPrice * StopLossPercentage / 100.0 / _Point; // Calculate order type of the last order int orderType }
错误分析
1. 语法错误
- 原
CalculateStopLoss函数末尾的int orderType语句未完成,既没有赋值也没有分号,直接截断,这是导致编译失败的直接原因。 - 函数逻辑不完整,没有计算止损价格就提前结束,缺少核心逻辑。
2. 逻辑错误
- 止损比例计算逻辑错误:原代码用
entryPrice * StopLossPercentage / 100.0 / _Point计算点数,会导致止损距离异常巨大(比如30%比例对应1.0价格时,会算出300000点,远超正常范围),正确逻辑应该是先算价格差,再处理点数。 - 订单选择逻辑冗余:开新单时调用止损计算,此时新单未成交,
OrdersTotal()获取的是历史订单,且马丁格尔策略需针对同方向订单累加止损,原代码未判断订单方向是否匹配。 - 初始订单止损处理错误:首次开单时无历史订单,函数直接返回0,导致止损设置无效。
修正后的完整代码
// Include the definition of OrderType and order types #include <Trade\Trade.mqh> //+------------------------------------------------------------------+ //| martin2.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //+------------------------------------------------------------------+ #property strict // Inputs input int RSIPeriod = 14; // RSI周期 input double OverboughtLevel = 70; // 超买水平 input double OversoldLevel = 30; // 超卖水平 input double InitialLotSize = 0.01; // 初始手数 input double MartingaleMultiplier = 2.0; // 马丁格尔乘数 input double StopLossPercentage = 30.0; // 止损比例(%) // 全局变量 int orderCount = 0; // 订单计数器 //+------------------------------------------------------------------+ //| 专家初始化函数 | //+------------------------------------------------------------------+ int OnInit() { return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| 专家反初始化函数 | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { } //+------------------------------------------------------------------+ //| 专家Tick函数 | //+------------------------------------------------------------------+ void OnTick() { double rsi = iRSI(_Symbol, PERIOD_CURRENT, RSIPeriod, PRICE_CLOSE, 0); // 获取当前RSI值 double currentBid = SymbolInfoDouble(_Symbol, SYMBOL_BID); // 当前买价 double currentAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK); // 当前卖价 // RSI高于超买水平,开空单 if (rsi > OverboughtLevel) { double lotSize = CalculateLotSize(); MqlTradeRequest request = {0}; MqlTradeResult result = {0}; // 填充卖单请求 request.action = TRADE_ACTION_DEAL; request.symbol = _Symbol; request.volume = lotSize; request.type = ORDER_TYPE_SELL; request.price = currentBid; request.sl = CalculateStopLoss(currentBid, ORDER_TYPE_SELL); // 传入订单类型 request.comment = "Martingale RSI"; request.type_time = ORDER_TIME_GTC; request.magic = 123456; request.deviation = 20; // 发送卖单 if (OrderSend(request, result)) { orderCount++; } else { Print("开空单错误: ", GetLastError()); } } // RSI低于超卖水平,开多单 if (rsi < OversoldLevel) { double lotSize = CalculateLotSize(); MqlTradeRequest request = {0}; MqlTradeResult result = {0}; // 填充买单请求 request.action = TRADE_ACTION_DEAL; request.symbol = _Symbol; request.volume = lotSize; request.type = ORDER_TYPE_BUY; request.price = currentAsk; request.sl = CalculateStopLoss(currentAsk, ORDER_TYPE_BUY); // 传入订单类型 request.comment = "Martingale RSI"; request.type_time = ORDER_TIME_GTC; request.magic = 123456; request.deviation = 20; // 发送买单 if (OrderSend(request, result)) { orderCount++; } else { Print("开多单错误: ", GetLastError()); } } } //+------------------------------------------------------------------+ //| 计算手数函数 | //+------------------------------------------------------------------+ double CalculateLotSize() { double lotSize = InitialLotSize * MathPow(MartingaleMultiplier, orderCount); // 确保手数符合平台最小/最大限制 lotSize = NormalizeDouble(lotSize, (int)SymbolInfoInteger(_Symbol, SYMBOL_VOLUME_DIGITS)); double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); return MathClamp(lotSize, minLot, maxLot); } //+------------------------------------------------------------------+ //| 计算止损价格函数 | //+------------------------------------------------------------------+ double CalculateStopLoss(double entryPrice, ENUM_ORDER_TYPE orderType) { double stopLossPrice = 0.0; double priceDiff = entryPrice * StopLossPercentage / 100.0; // 计算止损对应的价格差 // 根据订单类型计算止损价格 if (orderType == ORDER_TYPE_BUY) { // 多单止损在入场价下方 stopLossPrice = entryPrice - priceDiff; } else if (orderType == ORDER_TYPE_SELL) { // 空单止损在入场价上方 stopLossPrice = entryPrice + priceDiff; } // 确保止损价格符合平台价格精度要求 stopLossPrice = NormalizeDouble(stopLossPrice, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS)); // 检查止损是否符合平台最小止损距离要求 double minStopDistance = SymbolInfoDouble(_Symbol, SYMBOL_STOP_LEVEL) * _Point; double currentDistance = MathAbs(entryPrice - stopLossPrice); if (currentDistance < minStopDistance) { // 如果止损距离不足,调整到最小允许距离 if (orderType == ORDER_TYPE_BUY) { stopLossPrice = entryPrice - minStopDistance; } else { stopLossPrice = entryPrice + minStopDistance; } stopLossPrice = NormalizeDouble(stopLossPrice, (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS)); } return stopLossPrice; }
关键修改说明
- 修复语法错误:补全原代码截断的逻辑,完善
CalculateStopLoss函数结构。 - 修正止损计算逻辑:直接通过
entryPrice * 止损比例/100计算价格差,再根据订单方向确定止损价格,避免点数计算错误。 - 传入订单类型参数:调用止损计算时传入当前订单类型,确保止损方向正确。
- 添加平台规则适配:
- 手数计算时做归一化和范围限制,符合平台最小/最大手数要求。
- 止损价格做精度归一化,同时检查最小止损距离,避免因平台规则导致下单失败。
- 优化RSI调用:明确使用
PERIOD_CURRENT和PRICE_CLOSE参数,避免默认值歧义。
内容的提问来源于stack exchange,提问作者ulices
相关产品推荐
相关产品推荐

