恐怕这不是MT5的错误,而是你的代码的错误。顺便说一下,就像你报告的所有主题一样。你必须按照平台/语言的设计来处理,而不是像你认为的那样或希望的那样。
为什么你在OnCalculate()中使用ima.Create()?你得到了一个句柄,但数据还不可用,你得到了一个错误,然后你的代码就不会再被调用了。
P.S: "在没有数据访问的情况下工作 "是什么意思??恐怕这不是MT5的错误,而是你的代码的错误。顺便说一下,就像你报告的所有主题一样。你必须按照平台/语言的设计来处理,而不是像你认为的那样或希望的那样。
为什么你在OnCalculate()中使用ima.Create()?你得到了一个句柄,但数据还不可用,你得到了一个错误,然后你的代码就不会再被调用了。
P.S: "在没有数据访问的情况下工作 "是什么意思??恐怕这实际上是平台上的一个错误。我在Expert的OnInit()中运行同样的代码块,没有得到任何错误,而指标中的OnInit()却出现了错误。在没有数据访问的情况下工作,意味着它在离线、测试器或非市场时间工作。对任何指标的调用都应该 在任何时候从任何地方将其实例化,而平台在这些方面不 一致的事实意味着这不是一个功能,而是一个错误。把ima.Create放在oncalculate里面只是一个例子,因为它也不能 在任何不同的时间框架上实例化指标--从你在指标中调用它的任何地方,在第一个tick(数据更新)之前。我想再次强调,它在专家和脚本的任何地方都能正常工作,只是在指标中出现了一些问题。
好吧,你不相信我,那是你的权利,但你错了
我只能建议你写信给服务台,并请在这里报告他们的答案。
好吧,你不相信我,这是你的权利,但你错了。
我只能建议你写信给服务台,并请在这里报告他们的答复。
- 为什么你可以实例化同一时间段的指标并立即访问其数据?
这实际上意味着,你很幸运,数据已经有了。这并不能保证。它也可能失败。
这意味着,如果数据可以立即提供给脚本或EA,那么它同样可以提供给指标(因为这不是一个数据可用性问题)。该指标只是在OnCalculate()的第二次传递(也就是第一个tick)之前未能实例化。
我在诊断过程中考虑到了这一点。我甚至加入了循环和等待期,以备不时之需。和之前的人一样,我也遇到了同样的问题,这个特殊的错误。
这意味着,如果数据可以立即提供给脚本或EA,那么它同样可以提供给指标(因为这不是一个数据可用性问题)。该指标只是 在OnCalculate()的第二次传递(也就是第一个tick)之前未能实例化。
我在诊断过程中考虑到了这一点。我甚至加入了循环和等待期,以备不时之需。和之前的人一样,我在这个特殊的错误上也遇到了同样的问题。
你一直在重复 "实例化失败",但这并不准确。该指标在任何情况下都是实例化的。
问题是数据不能同步提供,你必须处理它。这不是MT5的错误,而是一个功能。
我建议停止讨论,等待SD的答复。
更新:请看下面的解决方法
当从一个指标的代码中调用一个不同时间框架的指标时,CopyBuffer()会抛出一个4806的错误(指标数据不可访问)。当调用一个有效的指标句柄到一个与当前工作时间段不同的时间段时,会发生这种情况。该错误只出现在初始化过程中,以及第一次调用OnCalculate()时,在第一个tick数据出现之前。为了隔离这个错误,我们采用了以下方法。
这是用于测试从脚本、EA和指标中调用CopyBuffer()时的输出的代码块。
ima.Create(_Symbol,PERIOD_H1,20,0,MODE_SMA,PRICE_CLOSE);
ima.Refresh();
CIndicatorBuffer *buff = ima.At(0);
int total = buff.Total();
Print(__LINE__," ",__FUNCSIG__," ",buff.Name()," Buffer size = ",total);
for(int i=0;i<total;i++){
if(i>2) break;
else{
Print(__LINE__," ",__FUNCSIG__," ",ima.PeriodDescription()," iMA(",i,") value = ",DoubleToString(ima.Main(i),_Digits));
}
}
完整的指标代码。
#include <Indicators\Trend.mqh>
#include <errordescription.mqh>
CiMA ima;
int m_bufferSize = -1;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
static int iCnt = 0;
//--- indicator buffers mapping
Print("-----------------------",TimeCurrent(),"--------------------------");
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
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[])
{
//---
if(rates_total != prev_calculated || m_bufferSize < 1 ){
ResetLastError();
ima.Create(_Symbol,PERIOD_H1,20,0,MODE_SMA,PRICE_CLOSE);
ima.Refresh();
CIndicatorBuffer *buff = ima.At(0);
m_bufferSize = buff.Total();
Print(__LINE__," ",__FUNCSIG__," ",buff.Name()," Buffer size = ",m_bufferSize);
if(m_bufferSize < 1){
Print(ErrorDescription(GetLastError()));
} else {
for(int i=0;i<m_bufferSize;i++){
if(i>2) break;
else{
Print(__LINE__," ",__FUNCTION__," ",ima.PeriodDescription()," iMA(",i,") value = ",DoubleToString(ima.Main(i),_Digits));
}
}
}
}
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
不收到错误的唯一方法是在H1图表上启动它(相同的TF)。
链接到有相同问题的论坛帖子。
https://www.mql5.com/en/forum/73274
https://www.mql5.com/en/forum/13676
https://www.mql5.com/en/forum/30958
https://www.mql5.com/en/forum/16614
解决方法。
解决方法是在OnInit()中创建指标并将EventSetMillisecondTimer设置为1ms。这允许OnCalculate()在第一遍后返回,并迅速调用OnTimer进行第二遍。只需要对OnTimer事件进行一次调用就可以解决,而且不需要再进行计算的时间延迟。
//| THROWAWAY.mq5 |
//| nicholishen |
//| www.reddit.com/u/nicholishenFX |
//+------------------------------------------------------------------+
#property copyright "nicholishen"
#property link "www.reddit.com/u/nicholishenFX"
#property version "1.00"
#property indicator_chart_window
#include <Indicators\Trend.mqh>
#include <errordescription.mqh>
CiMA ima;
int m_bufferSize = -1;
bool timedEvent = false;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
int waitMS = 1;
Print("-----------------------",TimeCurrent(),"--------------------------");
ima.Create(_Symbol,PERIOD_H1,20,0,MODE_SMA,PRICE_CLOSE);
EventSetMillisecondTimer(waitMS);
Print("OnTimer set to ",waitMS," ms");
//---
return(INIT_SUCCEEDED);
}
void OnTimer()
{
//---
ima.Refresh();
EventKillTimer();
timedEvent = true;
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
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[])
{
static int tickCnt = 0;
tickCnt++;
if(!timedEvent)return rates_total;
//---
if(rates_total != prev_calculated || m_bufferSize < 1 ){
ResetLastError();
CIndicatorBuffer *buff = ima.At(0);
m_bufferSize = buff.Total();
if(m_bufferSize <=0) ima.Refresh();
// try wait with looping
if(m_bufferSize < 1){
Print(ErrorDescription(GetLastError()));
} else {
for(int i=0;i<m_bufferSize;i++){
if(i>2) break;
else{
Print(__LINE__," ",__FUNCTION__,buff.Name(),
" Buffer size = ",m_bufferSize,
" | ",ima.PeriodDescription()," iMA(",i,") value = ",
DoubleToString(ima.Main(i),_Digits),
" | Tick-count = ",tickCnt
);
}
}
}
}
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+