[解決済み] 異なる作業時間枠のインディケータから呼び出され作成された場合、インディケータが適切にインスタンス化されない。

 

UPDATE: 以下のワークアラウンドを参照してください。

インジケーターのコード内から異なるTime-Frameのインジケーターを呼び出すと、CopyBuffer()で4806(Indicator data not accessible)のエラーが投げられる。これは、現在の作業時間枠とは異なる時間枠に対して有効なインディケータ・ハンドルを呼び出すと発生します。このバグは、初期化および最初のティックデータ前のOnCalculate()の最初の呼び出しの間のみ表示されます。バグを分離するために、以下のメソッドを適用しました。

これは、スクリプト、EA、およびインジケータから呼び出されたときにCopyBuffer()の出力をテストするために使用されるコードのブロックです。

#include <Indicators\Trend.mqh>


   CiMA ima;
   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));  
      }
   }

完全なインジケータコード。

#property indicator_chart_window

#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()が最初のパスの後に戻り、2回目のパスのためにOnTimerを迅速に呼び出すことができました。OnTimerイベントを1回呼び出すだけで修正でき、計算のためにそれ以上の時間遅れは必要ありませんでした。

//+------------------------------------------------------------------+
//|                                                    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);
}
//+------------------------------------------------------------------+
Error 4806 while copying buffers
Error 4806 while copying buffers
  • www.mql5.com
com/en/articles/100, but tried to change it to use the CCI indicator only.
 
どなたか回避策をご存知の方はいらっしゃいますか?
 

これは、MT5のバグではなく、あなたのコードのバグだと思います。ところで、あなたが報告した他のトピックと同様です。プラットフォームや言語は、あなたが考えたり、そうしたいと思うようなものではなく、設計されたとおりに対処する必要があります。

OnCalculate()でima.Create()を使っているのはなぜですか?ハンドルを取得しても、データはまだ利用できませんし、エラーが発生した後、あなたのコードは二度と呼び出されません。

追伸:"Works without data access." の意味は何ですか??
 
Alain Verleyen:

これは、MT5のバグではなく、あなたのコードのバグだと思います。ところで、あなたが報告した他のトピックと同様です。プラットフォームや言語は、あなたが考えたり、そうしたいと思うようなものではなく、設計されたとおりに対処する必要があります。

OnCalculate()でima.Create()を使っているのはなぜですか?ハンドルを取得しても、データはまだ利用可能ではなく、エラーが発生し、あなたのコードは二度と呼び出されません。

追伸:"Works without data access." の意味は何ですか??
これはプラットフォームのバグだと思います。エキスパートのOnInit()で全く同じコードブロックを実行してもエラーにならないのに、インジケータのOnInit()ではエラーを投げています。データアクセスなしで動作するということは、オフライン、テスター、または市場時間外に動作するということです。インジケーターの呼び出しは、いつでもどこからでもインスタンス化できるはずで、その点でプラットフォームが矛盾しているということは、これは機能ではなくバグであるということです。ima.Createをoncalculateの中に持っているのはほんの一例で、別の時間枠で、つまりインディケータ内で呼び出したところから、最初のティック(データ更新)前に、インディケータをインスタンス化することにも失敗しています。無限に更新することができますが、oncalculateが正確に1回実行され、その後戻るまで、それはインジケータデータにアクセスしません。新しいティックが入ると、その次のパスで動作します。バグ

もう一度強調しておきますが、エキスパートやスクリプトではどこからでも正しく動作しますが、インジケータではなぜか壊れています。

 
nicholishen:
実はこれ、プラットフォームのバグなんです。エキスパートのOnInit()で全く同じコードブロックを実行してもエラーにならないのに、インジケータのOnInit()ではエラーを投げています。データアクセスなしで動作するということは、オフライン、テスター、または市場時間外に動作するということです。インジケーターの呼び出しは、いつでもどこからでもインスタンス化できるはず で、その点でプラットフォームが矛盾して いるということは、これは機能ではなくバグであるということです。ima.Createをoncalculateの中に持っているのはほんの一例で、これはまた、別の時間枠で、つまり、最初のティック(データ更新)の前に、インジケータ内のどこからでもそれを呼び出して、インジケータをインスタンス化することに失敗 するからです。繰り返しになりますが、エキスパートやスクリプトでは正常に動作しますが、インジケータでは何らかの理由で動作しないことがあることを強調しておきます。

私の言うことを信じないのは勝手ですが、それは間違いです。

サービスデスクに 連絡し、その回答をここに報告することをお勧めします。

 
Alain Verleyen:

あなたは私を信じていない、それはあなたの権利ですが、あなたは間違っています。

サービスデスクに 連絡し、その回答をここで報告することをお勧めします。

ありがとうございます、そうします。もし私が間違っているなら、なぜエキスパートやスクリプトでは動作するのに、インジケータからは動作しないのでしょうか?
 
nicholishen:
ありがとうございます、そうします。もし私が間違っているなら、なぜエキスパートとスクリプトでは動作し、インジケータからは動作しないのでしょうか?

シンボルのすべてのインジケータが同じスレッドで実行されるからです。Strategy Testerと EAとスクリプトは状況が違いますね。

しかし、ServiceDeskの回答を見てみましょう。多分私は間違っている :-)

 
Alain Verleyen:

シンボルのすべてのインジケータが同じスレッドで実行されるからです。Strategy Testerと EAとスクリプトは別の状況です。

ServiceDeskの回答を見てみましょう。もしかしたら、私が間違っているかもしれません:-)

ということを考えましょう...。

  • 同じ時間枠のインジケータはインスタンス化してすぐにデータにアクセスできるのに、なぜ違う時間枠のインジケータはできないのでしょうか?
 
nicholishen:
  • なぜ同じタイムフレームのインジケータをインスタンス化し、そのデータにすぐにアクセスできるのか?

これは実は、データがすでに利用可能であることが幸運であることを意味します。これは保証されたものではありません。また、失敗する可能性もあります。
 
Stanislav Korotky:
これは実際には、データがすでに利用可能であることが幸運であることを意味します。これは保証されたものではありません。また、失敗する可能性もあります。

これは、データがスクリプトまたはEAですぐに利用可能であれば、インディケータでも同様に利用可能であることを意味します(これはデータ利用可能性の問題ではありません)。インジケータは、OnCalculate()の2回目のパス(別名、最初のティック)の前にインスタンス化に失敗しているに過ぎません。

私は診断の間、これを考慮に入れました。念のため、ループと待機期間も組み込んでおきました。このバグについては、私も同じ問題を抱えています。

 
nicholishen:

これは、データがスクリプトまたはEAですぐに利用可能であれば、インディケータでも同様に利用可能であることを意味します(これはデータ利用可能性の問題ではありません)。インジケータは、OnCalculate()の2回目のパス(別名、最初のティック)の前にインスタンス化に失敗しているに過ぎません

私は診断の間、これを考慮に入れました。念のため、ループと待機期間も組み込んでおきました。私の前の皆と同じように、私もこの特別なバグで同じ問題を抱えています。

インスタンス化に失敗する」と繰り返していますが、これは正確ではありません。インジケータはすべてのケースでインスタンス化されます。

問題は、データが同期的に利用できないことで、それに対処する必要があります。これはMT5のバグではなく、機能です。

議論を中断し、SDの回答を待つことを提案します。