You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

关键修改说明

  1. 修复语法错误:补全原代码截断的逻辑,完善CalculateStopLoss函数结构。
  2. 修正止损计算逻辑:直接通过entryPrice * 止损比例/100计算价格差,再根据订单方向确定止损价格,避免点数计算错误。
  3. 传入订单类型参数:调用止损计算时传入当前订单类型,确保止损方向正确。
  4. 添加平台规则适配:
    • 手数计算时做归一化和范围限制,符合平台最小/最大手数要求。
    • 止损价格做精度归一化,同时检查最小止损距离,避免因平台规则导致下单失败。
  5. 优化RSI调用:明确使用PERIOD_CURRENT和PRICE_CLOSE参数,避免默认值歧义。

内容的提问来源于stack exchange,提问作者ulices

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 21:07:03