You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

无法通过MQL5指标返回值:EA调用获取结果始终为0问题排查

解决MQL5指标被EA调用时返回值始终为0的问题

我帮你排查了代码里的几个关键问题,这就是为什么EA拿不到正确值的原因:

核心错误点及修正方案

1. EA根本没读取指标数据

你的EA代码里CopyBuffer被注释掉了!这就相当于你打开了冰箱门但没伸手拿东西,remaining_time数组一直是空的,自然输出0。必须启用CopyBuffer来从指标缓冲区拉取数据,还要加错误检查确保读取成功。

2. 指标缓冲区没设置序列模式

指标里的remainingtime缓冲区没有开启序列模式(ArraySetAsSeries),但EA里把remaining_time设成了序列模式,两边模式不匹配,导致EA读错了位置。指标缓冲区必须和K线时间序列保持一致,才能拿到最新的数值。

3. 剩余时间计算逻辑有漏洞

原来的计算int m=int(time[0]+PeriodSeconds()-TimeCurrent());在K线刚切换时会得到负数,导致s变成负数值,虽然Print可能暂时显示正常,但会给EA传递异常数据。得先判断剩余时间是否为正,负数就设为0。

4. EA缺少必要的错误检查

EA里没有检查指标是否成功加载,也没判断CopyBuffer是否执行成功,出问题了根本不知道哪里错。


修正后的完整代码

修正后的指标代码

#property indicator_chart_window
#property strict
#property indicator_buffers 1

//---- input parameters
input color Clock_Color = clrWhite;
input ENUM_BASE_CORNER Corner = CORNER_LEFT_LOWER;
string objname="Spread&Bar";
double s1[];
double remainingtime[];

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer(0,remainingtime,INDICATOR_CALCULATIONS);
   // 新增:将缓冲区设置为序列模式,和K线时间保持一致
   ArraySetAsSeries(remainingtime, true);
   
   ObjectCreate(0, objname, OBJ_LABEL,0, 0, 0);
   ObjectSetInteger(0, objname, OBJPROP_CORNER, Corner);
   ObjectSetInteger(0, objname, OBJPROP_XDISTANCE, 10);
   ObjectSetInteger(0, objname, OBJPROP_YDISTANCE, 2);
   ENUM_ANCHOR_POINT Anchor = ANCHOR_LEFT_UPPER;
   switch (Corner)
   {
      case CORNER_LEFT_UPPER: Anchor=ANCHOR_LEFT_UPPER; break;
      case CORNER_RIGHT_UPPER: Anchor=ANCHOR_RIGHT_UPPER; break;
      case CORNER_LEFT_LOWER: Anchor=ANCHOR_LEFT_LOWER; break;
      case CORNER_RIGHT_LOWER: Anchor=ANCHOR_RIGHT_LOWER; break;
   }
   ObjectSetInteger(0, objname, OBJPROP_ANCHOR, Anchor);
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   ObjectDelete(0, objname);
}

//+------------------------------------------------------------------+
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& spreads[])
{
   ArraySetAsSeries(time, true);
   
   // 修正剩余时间计算逻辑,确保非负
   datetime next_bar_time = time[0] + PeriodSeconds();
   long remaining_seconds = next_bar_time - TimeCurrent();
   if(remaining_seconds < 0) remaining_seconds = 0;
   
   int m = (int)(remaining_seconds / 60);
   int s = (int)(remaining_seconds % 60);
   
   long spread=SymbolInfoInteger(Symbol(), SYMBOL_SPREAD);
   string _sp="",_m="",_s="";
   if(spread<10) _sp="..";
   else if(spread<100) _sp=".";
   if(m<10) _m="0";
   if(s<10) _s="0";
   
   ObjectSetString(0, objname, OBJPROP_TEXT, 
                   "Spread: " +IntegerToString(spread)+_sp+" Next Bar in "+_m+IntegerToString(m)+":"+_s+IntegerToString(s));
   remainingtime[0] = remaining_seconds; // 这里如果需要返回秒数部分,改成s即可
   Print(remainingtime[0]);
   
   ObjectSetInteger(0, objname, OBJPROP_FONTSIZE, 10);
   ObjectSetInteger(0, objname, OBJPROP_COLOR, Clock_Color);
   ObjectSetString(0, objname, OBJPROP_FONT, "Courier");
   
   return(rates_total);
}

修正后的EA代码

#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int candletime;
double remaining_time[];

int OnInit()
{
   //--- 加载指标,注意文件名要和编译后的ex5文件名一致
   candletime = iCustom(_Symbol,_Period,"candle_time_end_and_spread");
   if(candletime == INVALID_HANDLE)
   {
      Print("Failed to load indicator! Error code: ", GetLastError());
      return(INIT_FAILED);
   }
   ArraySetAsSeries(remaining_time,true);
   //---
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   //--- 释放指标句柄,避免内存泄漏
   if(candletime != INVALID_HANDLE)
   {
      IndicatorRelease(candletime);
      candletime = INVALID_HANDLE;
   }
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   //--- 从指标的第0号缓冲区读取最新1个数据
   if(CopyBuffer(candletime, 0, 0, 1, remaining_time) != 1)
   {
      Print("CopyBuffer failed! Error code: ", GetLastError());
      return;
   }
   //--- 打印获取到的剩余时间
   Print("Remaining time to next bar: ", remaining_time[0], " seconds");
   ArrayPrint(remaining_time);
}

额外说明

  • 确保指标编译后的文件名和EA里iCustom调用的名称完全一致(比如如果指标编译后是candle_time_end_and_spread.ex5,EA里写"candle_time_end_and_spread"即可,不用加后缀)。
  • 如果你需要EA获取的是原来的秒数部分(不是总剩余秒数),把指标里remainingtime[0] = remaining_seconds;改成remainingtime[0] = s;就行。

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

火山引擎 最新活动