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

基于RSI穿越50绘制箭头的MQL4指标无显示求助

问题排查与代码修复

你的代码逻辑能正确触发打印语句,但箭头不显示,核心问题在于缓冲区序列对齐错误、RSI句柄重复创建以及缓冲区未初始化这几个关键点。以下是具体问题分析和修复后的代码:

核心问题分析

  1. RSI句柄在OnCalculate中重复创建
    每次调用OnCalculate时都用iRSI创建新句柄,会导致资源泄漏,且新创建的句柄可能未完成数据加载,影响CopyBuffer的正确性。

  2. 箭头缓冲区未设置为序列模式
    你将RSIArray和PriceInfo设为序列数组(最新 bar 索引为0),但箭头缓冲区upArrow、downArrow未做同样设置,导致赋值的箭头位置与实际 bar 索引错位,箭头被绘制到了不可见的历史 bar 上。

  3. 缓冲区未初始化空值
    未满足条件的 bar 未将缓冲区值设为EMPTY_VALUE(即你设置的0.0),可能残留旧值或导致绘图逻辑异常。

  4. 未初始化的draw变量
    draw变量未赋值就用于PLOT_DRAW_BEGIN,虽默认值为0不影响,但显式初始化更规范。

修复后的完整代码

#property indicator_chart_window    
#property indicator_buffers 2
#property indicator_width1  2
#property indicator_width2  2
#property indicator_color1 clrRed
#property indicator_color2 clrGreen

double upArrow[], downArrow[];
int rsiHandle; // 全局存储RSI句柄

int OnInit(){
   // 初始化RSI句柄
   rsiHandle = iRSI(Symbol(), Period(), 14, PRICE_CLOSE);
   if(rsiHandle == INVALID_HANDLE){
      Print("创建RSI句柄失败");
      return INIT_FAILED;
   }

   IndicatorSetString(INDICATOR_SHORTNAME,"Arrow");
   
   // 配置买箭头缓冲区
   PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_ARROW);
   PlotIndexSetInteger(0, PLOT_ARROW, 233);
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
   PlotIndexSetString(0, PLOT_LABEL, "Buy");
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 0); // 显式设置从第0根bar开始绘制
   SetIndexBuffer(0, upArrow);
   ArraySetAsSeries(upArrow, true); // 设置为序列模式

   // 配置卖箭头缓冲区
   PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_ARROW);
   PlotIndexSetInteger(1, PLOT_ARROW, 234);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0.0);
   PlotIndexSetString(1, PLOT_LABEL, "Sell");
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, 0);
   SetIndexBuffer(1, downArrow);
   ArraySetAsSeries(downArrow, true); // 设置为序列模式

   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason){
   // 释放RSI句柄,避免资源泄漏
   if(rsiHandle != INVALID_HANDLE){
      IndicatorRelease(rsiHandle);
   }
}

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   int limit = rates_total - prev_calculated;
   if(limit <= 0) return rates_total;

   double RSIArray[];
   ArraySetAsSeries(RSIArray, true);
   // 复制RSI数据并检查结果
   int copiedRSI = CopyBuffer(rsiHandle, 0, 0, limit, RSIArray);
   if(copiedRSI != limit){
      Print("复制RSI数据失败,仅复制", copiedRSI, "条");
      return rates_total;
   }

   // 初始化缓冲区为空值,确保未满足条件的bar不显示箭头
   for(int i = 0; i < limit; i++){
      upArrow[i] = 0.0;
      downArrow[i] = 0.0;
   }

   // 遍历检测RSI交叉信号
   for(int i = limit - 1; i >= 1; i--){
       double rsi_current = RSIArray[i];
       double rsi_prev = RSIArray[i+1];

       // RSI上穿50
       if(rsi_prev < 50 && rsi_current >= 50){          
          upArrow[i] = low[i] - 10 * Point(); // 绘制在当前bar的下方
          Print("RSI上穿50,bar索引:", i, ",收盘价:", close[i]);
       }
       // RSI下穿50
       else if(rsi_prev > 50 && rsi_current <= 50){
          downArrow[i] = high[i] + 10 * Point(); // 绘制在当前bar的上方
          Print("RSI下穿50,bar索引:", i, ",收盘价:", close[i]);
       }
   }

   return(rates_total);
}

关键修复说明

  • RSI句柄管理:在OnInit中创建一次RSI句柄,OnDeinit中释放,避免资源泄漏和数据加载异常。
  • 缓冲区序列对齐:将upArrow和downArrow设为序列模式,确保赋值的索引与实际bar位置对应。
  • 缓冲区初始化:每次计算前将新bar的缓冲区值设为空值,避免残留旧数据。
  • 交叉信号逻辑优化:调整循环范围,确保i+1不越界,同时将箭头绘制在信号触发的当前bar上(若需保留原逻辑绘制在前一根bar,可改回low[i+1])。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 19:05:56