[SERVICE DESK】タイマーでシニアTFの時刻を取得する際にエラーが発生!?

 

目的: インディケータを起動する際に、週足、日足、時間足のバーの開始時間という現在のデータをタイマーで取得する。そして、それらをグローバル変数に書き込んで、さらに使用する。現在のタイムフレームはМ1です。

実装: SeriesInfoInteger()関数を用いてバータイムを取得する。

#property version   "1.00"
#property strict
#property indicator_chart_window
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//--- Время открытия текущего часа, дня и недели
datetime _weekOpenTime = 0;
datetime _hourOpenTime = 0;
datetime _dayOpenTime=0;
//--- Вести лог журнала
const bool inpFileLog=true;
//--- Количество секунд в одном дне
const int SEC_PER_DAY=86400;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Запускаем таймер
   if(!EventSetMillisecondTimer(20))
     {
      Print(__FUNCTION__,": ОШИБКА #",GetLastError(),": таймер с частотой 20 ms не установлен!");
      return( INIT_FAILED );
     }
//--- Сбрасываем время открытия текущего часа, дня и недели
   _weekOpenTime= 0;
   _dayOpenTime = 0;
   _hourOpenTime= 0;
//---
   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[])
  {

   return( rates_total );
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//--- Проверяем, записано ли время открытия текущей недели
   if(!CheckCurrentWeekOpenTime())                        // Если время не записано
      return;                                                // Выходим
//--- Проверяем, записано ли время открытия текущего дня
   if(!CheckCurrentDayOpenTime())                        // Если время не записано
      return;                                                // Выходим
//--- Проверяем, записано ли время открытия текущего часа
   if(!CheckCurrentHourOpenTime())                        // Если время не записано
      return;                                                // Выходим
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущей недели             |
//+------------------------------------------------------------------+
bool CheckCurrentWeekOpenTime()
  {
//--- Проверяем, записано ли время
   if(_weekOpenTime==0) // Если время не записано
     {
      //--- Получаем время открытия недельного бара
      ResetLastError();
      const datetime weekBarOpenTime=(datetime)SeriesInfoInteger(_Symbol,PERIOD_W1,SERIES_LASTBAR_DATE);
      const int err=GetLastError();
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия недельного бара = "+TimeToString(weekBarOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущей недели через iTime = "+TimeToString( weekOpenTime2 )+". Ошибка #",err2 );
        }
      //ResetLastError();
      //const datetime weekBarOpenTime2 = iTime( _Symbol, PERIOD_W1, 0 );
      //const int err2 = GetLastError();
      //--- Проверяем, получено ли время открытия недельного бара
      if(weekBarOpenTime==0 || err!=0) // Если время бара не получено или история обновляется
         return(false);                              // Возвращаем ложь
      //--- Запоминаем время открытия текущей недели (время открытия недельного бара - воскресенье)
      _weekOpenTime=weekBarOpenTime+SEC_PER_DAY;
      //const datetime weekOpenTime2 = weekBarOpenTime2+SEC_PER_DAY;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущей недели = "+TimeToString(_weekOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущей недели через iTime = "+TimeToString( weekOpenTime2 )+". Ошибка #",err2 );
        }
      //--- Возвращаем истину
      return( true );
     }
//--- Время открытия недели ранее записано. Возвращаем истину
   return( true );
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущего дня                  |
//+------------------------------------------------------------------+
bool CheckCurrentDayOpenTime()
  {
//--- Проверяем, записано ли время
   if(_dayOpenTime==0) // Если время не записано
     {
      //--- Получаем время открытия дневного бара
      ResetLastError();
      const datetime tempDayOpenTime=(datetime)SeriesInfoInteger(_Symbol,PERIOD_D1,SERIES_LASTBAR_DATE);
      const int err=GetLastError();
      //ResetLastError();
      //const datetime dayOpenTime2 = iTime( _Symbol, PERIOD_D1, 0 );
      //const int err2 = GetLastError();
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия текущего дня = "+TimeToString(tempDayOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущего дня iTime = "+TimeToString( dayOpenTime2 )+". Err2 #",err2 );
        }
      //--- Проверяем, получено ли время открытия дневного бара
      if(tempDayOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь
      //--- Сохраняем в глобальную переменную значение открытия текущего дня
      _dayOpenTime=tempDayOpenTime;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущего дня = "+TimeToString(_dayOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущей недели через iTime = "+TimeToString( weekOpenTime2 )+". Ошибка #",err2 );
        }
      //--- Возвращаем истину
      return( true );
     }
//--- Время открытия дня ранее записано. Возвращаем истину
   return( true );
  }
//+------------------------------------------------------------------+
//| Проверяем, записано ли время открытия текущего часа              |
//+------------------------------------------------------------------+
bool CheckCurrentHourOpenTime()
  {
//--- Проверяем, записано ли время
   if(_hourOpenTime==0) // Если время не записано
     {
      //--- Получаем время открытия часового бара
      ResetLastError();
      const datetime tempHourOpenTime=(datetime)SeriesInfoInteger(_Symbol,PERIOD_H1,SERIES_LASTBAR_DATE);
      const int err=GetLastError();
      //const datetime hourOpenTime2 = iTime( _Symbol, PERIOD_H1, 0 );
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Время открытия текущего часа = "+TimeToString(tempHourOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущего часа iTime = "+TimeToString( hourOpenTime2 ) );
        }
      //--- Проверяем, получено ли время открытия часового бара
      if(tempHourOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь
      //---
      _hourOpenTime=tempHourOpenTime;
      //---
      if(inpFileLog)
        {
         Print(__FILE__,": Актуальное время открытия текущего часа = "+TimeToString(_hourOpenTime)+". Ошибка #",err);
         //Print( __FILE__,": Время открытия текущего часа iTime = "+TimeToString( hourOpenTime2 ) );
        }
      //--- Возвращаем истину
      return( true );
     }
//--- Время открытия часа ранее записано. Возвращаем истину
   return( true );
  }

結果: 例えば、夜間停止していた端末が数時間稼働して いた場合、最初の(1日)起動時にそのような結果が得られます。

2018.09.21 11:11:27.306 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Актуальное время открытия текущего часа = 2018.09.20 16:00. Ошибка #0
2018.09.21 11:11:27.306 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия текущего часа = 2018.09.20 16:00. Ошибка #0
2018.09.21 11:11:27.280 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия текущего часа = 2018.09.20 16:00. Ошибка #4066
2018.09.21 11:11:27.279 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Актуальное время открытия текущего дня = 2018.09.20 00:00. Ошибка #0
2018.09.21 11:11:27.279 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия текущего дня = 2018.09.20 00:00. Ошибка #0
2018.09.21 11:11:27.265 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия текущего дня = 2018.09.20 00:00. Ошибка #4066
2018.09.21 11:11:27.264 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Актуальное время открытия текущей недели = 2018.09.17 00:00. Ошибка #0
2018.09.21 11:11:27.264 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия недельного бара = 2018.09.16 00:00. Ошибка #0
2018.09.21 11:11:27.233 test_isNewDayInTimer USDCHF.e,M1: test_isNewDayInTimer.mq4: Время открытия недельного бара = 2018.09.16 00:00. Ошибка #4066
2018.09.21 11:11:27.066 test_isNewDayInTimer USDCHF.e,M1: initialized
2018.09.21 11:11:27.055 Custom indicator test_isNewDayInTimer USDCHF.e,M1: loaded successfully

ご覧の通り、データ取得時刻は2018.09.21 11:11で、その時刻に対して、日の開始時刻=2018.09.20(本来は2018.09.21だが)、時間の開始時刻=2018.09.20 16:00(本来は2018.09.21 11:00だが)が得られていることがわかります。そして、端末が返す時刻は、最後に閉じた時のデータに他ならない。つまり、端末がシャットダウンされても、データはキャッシュされ、返されます。そして、データが更新されるまで、毎回エラー#4066が返される(更新状態の履歴データを要求)ならわかるのですが、そうではなく、返されるのはERRORデータなのです!?このエラーは一度だけ返されるので、その後は我慢してください。明らかなキャッシングエラーが発生しています。開発者(@Slava) には、ぜひ注目してもらいたいですね。

繰り返す。タイマーで要求すると、誤ったデータが表示される!

端末のバージョン: x64、1090。

 
つまり、4066エラーはMTFインデックスの典型的な問題で、端末が他のTFのデータを供給していない、他のTFのデータの整合性を確認する必要がある。
 
Vitaly Gorbunov:
まあ、だからエラー4066は、MTFのインデュサーのための典型的な問題であり、端末は他のTFのデータの整合性をチェックする必要がある他のTFのデータをポンプされていないです。

アドバイスをする前に、コードと私が書いたものをよく見てください。

このコードには、エラーに対するチェックと、空のデータに対するチェックがあります。そして、関数がエラーにならずに不正なデータを返すと、それはエラーになるのです!

 
Alexey Kozitsyn:

アドバイスをする前に、コードと私が書いたものをよく見てください。

このコードには、エラーに対するチェックと、空のデータに対するチェックがあります。そして、関数がエラーにならずに不正なデータを返すと、それはエラーになるのです!

何か見落としているかもしれませんが、例えばCheckCurrentHourOpenTime()プロシージャで、履歴の整合性をチェックする箇所を教えてください。
 
Vitaly Gorbunov:
例えば、CheckCurrentHourOpenTime() プロシージャで、履歴の整合性をチェックする箇所を教えてください。

ストーリー・インテグリティとはどういう意味ですか?

履歴値を取得する際に、エラーチェックがあるという話です。どの機能にもチェックが入っています。これです。

//--- Проверяем, получено ли время открытия часового бара
      if(tempHourOpenTime==0 || err!=0) // Если время бара не получено
         return(false);                                 // Возвращаем ложь

つまり、ゼロ値またはエラーを受け取った場合、グローバル変数 に時刻を書き込まない。物足りないと思いますか?

ポイントは、SeriesInfoInteger()関数が最初はエラーを返しますが、次に実行するとNO!そして、正しい値も返さないのです!
 

SeriesInfoInteger() は、特定のクエリに関する情報のみを返します。この場合、シンボルと期間による履歴の中で、最後に判明したバーの 開始時刻を 返すように要求しています。ここではエラーはなく、その時点で最新だったものが返されます。履歴の整合性を確認する方法を紹介します。

 
Vitaly Gorbunov:

SeriesInfoInteger() は、特定のクエリに関する情報のみを返します。この場合、シンボルと期間による履歴の中で、最後に知られているバーの 開始時刻を 返すように要求しています。ここではエラーはなく、その時点で最新だったものが返されます。PCに取り付き、履歴の整合性を確認する方法を紹介します。

ここにエラーはないってこと!?では、なぜ "偽 "のエラーコードを出すのでしょうか?履歴がないところはOKと書いてあるのに...。

 
Alexey Kozitsyn:

ここにエラーがないってどういうこと!?では、なぜ「偽」のエラーコードを出しているのでしょうか?履歴がないところはOKと書いてあるのに...。

もう一度言いますが、この関数は履歴の整合性をチェックするものではありませんその中で見つけられた情報を返します。このケースでは、端末がシャットダウンされたときに要求されたアワーバーを発見しました。残りの履歴はまだ読み込まれていません。

 

与えられたTFの履歴が完全にページングされているかどうかを確認するには、単に関数を使用します。

bool IsTFDataReady(ENUM_TIMEFRAMES eTF)
{
   ResetLastError();
   iTime(NULL, eTF, 1);
   return GetLastError() == ERR_NO_ERROR;
}

この関数が false を返した場合、要求された TF のデータは不完全である。それ以外は完全なものです。

 
Vitaly Gorbunov:

もう一度言いますが、この機能はストーリーの整合性をチェックするものではありませんその中で見つけることができた情報を返します。この場合、端末がシャットダウンされたときに要求されたアワーバーを見つけた。残りの履歴はまだ読み込まれていません。

もう一度言います。どこにも書いてないんですけどね。それがまず第一です。次に、ではなぜ最初にエラーコード 4066を表示し、その後表示しないことで誤解を招くのでしょうか?

 
Ihor Herasko:

与えられたTFの履歴が完全にページングされているかどうかを確認するには、単に関数を使用します。

この関数が false を返した場合、要求された TF のデータは不完全である。それ以外は完全なものです。

タイマーで確認しましたか?コメントアウトした行があるのがわかりますか?この機能を確認したところ、全くエラーが表示されず、また誤ったデータも表示されました。もう一度確認します。

理由: