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

 
ぜひ、開発者の方々のご意見をお聞かせください。
 
 ResetLastError();
      if(iBarShift(Symbol(),PERIOD_M15,TimeCurrent(),true)==-1)
        {
         Print(__FILE__+": Данные истории по последнему часу отсутствуют! Ошибка #",GetLastError());
         return( false );
        }
      //---
      if(GetLastError()==ERR_NO_ERROR)
        {
         ResetLastError();
         //--- Запоминаем время открытия бара
         _m15OpenTime=iTime(NULL,PERIOD_M15,0);
         //---
         Print(__FILE__,": Актуальное время открытия бара М15 = "+TimeToString(_m15OpenTime)+". Ошибка #",GetLastError());
         //--- Возвращаем истину
         return( true );
        }
 
Alexey Kozitsyn:

最も確実な解決策は、取引サーバーへの接続を確認しながらOnCalculate()の呼び出しを 待つことだと思われます。接続チェック(IsConnected())をしないと、OnCalculate()でも端末読み込み時に取得することになります。

しかし、すべての疑問が解消されるわけではありません。

1.IsConnected()のドキュメントには、OnCalculate()でシニアTFから(少なくとも)データを受け取る前に必ず呼ばれなければならないと書かれていないのはなぜでしょうか?

2.OnTimer()内のIsConnected()が実際に動作しないのはなぜですか?トレードサーバーとの接続を確立するということは、データが取得できるということではないのでしょうか。

3.トレードサーバとの接続を確立し、OnTimer()でデータを受信しようとした場合、iTime()、iBarShift()、SeriesInfoInteger()やそれに類する関数は、情報を取得するこの特定のトレードサーバからのデータがまだ同期されていなければエラーを返すべきではないでしょうか。そうでなければ、エラー4066を一度だけ返して、あとは手持ちのデータを使ってくださいとか、意味不明なことになります。

私は開発者とそこにいる友人の一人と話し、次のことを伝えています:1 私はどうしたらいいのでしょうか?

1 無意味です、いつでも、どこからでもかけられます。

2 IsConnectedはコードのどこからでも呼び出すことができ、動作しますが、エラースタックに何も書き込まず、true/falseを返して終わりという関数です。接続手順がかなり(最低1秒)長く、ログイン時にIsConnectedが発生することを考慮すると、端末起動時に接続状態を確認し、引用フローが開始されるのを待つ必要がある。

3 これらの関数は、エラースタックに何も書き込まず、自分自身で結果を返します。

なぜ4066になったかというと、このエラーはTimeCurrent関数が原因です。端末がログインして、サーバーに時間を要求するのも、回線品質によっては時間がかかるので、クイックタイマーを用意しています。そして、TimeCurrentからのリクエストで4066を得た。そして、時刻を取得して関数が正常に動作するようになり、その関数自身がエラースタックを迂回して動作した結果、エラーを返すようになりました。

このような場合、クイックタイマーで端末を起動し、サーバーからのデータ受信を開始したことを確認することをお勧めします。私のバージョンはちょっとひつこいですね、OnCalculateから信号をもらってデータの受信を開始するのが正しいでしょう。

 
もっと単純な話です。
 
Alexey Kozitsyn:

問題を解決するために、どのようなことを提案しますか(ありますか、あなたの意見で)。OnCalculate() が1-2回呼ば れるまで待つ?

はい、その通りです。OnInit()では、結果を確認せずに必要なTFを呼び出すだけ(そこでは当てにならない)、OnCalculateでは、関数IsTFDataReady()を呼び出します。要求されたすべてのTFに対してtrueが返されたら、すぐにインジケーターのアルゴリズムの実行を開始することができます。

 
Alexey Kozitsyn:

1.IsConnected()のドキュメントには、OnCalculate()でシニアTFから(少なくとも)データを受信する前に必ず呼び出さなければならないと書かれていないのはなぜですか?

IsConnected()はかなりトリッキーな関数です。サーバーへの接続状態を1つだけ返します。しかし、端末は複数の接続を使用します。単体で8本のトレードスレッドがあります。そのため、IsConnected()がtrueを返しても、それが何を意味するのかがよくわからない。少なくとも、タイムスリップが要求され、構築されることは期待できない。しかし、IsConnected()がfalseを返した場合、端末がまだオフラインであることを確認することができます。

端末の接続の 有無が重要なタスクとは何でしょうか?私が理解する限り、インジケータはデータを視覚化するためのツールです。というデータがあります。新しいデータが届くと、ビジュアライゼーションが更新されます。データの関連性の確認は不要とすべき。それが端末の仕事です。

 
Igor Makanu:

MQL5の話だと思いますが、OHLCの準備はMT4と同じではありません。

MT4についてです。2-3年前くらいに、Time[0]のバグをキャッチしていました。開発者はそれを修正したようですが、その後、時間が経つと再び現れました。問題は、このバグを一義的に再現することが不可能なことです。

 
Ihor Herasko:

IsConnected()は、かなりトリッキーな関数です。サーバーへの接続のうち、1つの状態を返すだけである。しかし、端末は複数の接続を使用します。トレードスレッドだけで8つもあるんですよ。そのため、IsConnected()がtrueを返しても、それが何を意味するのかがよくわからない。少なくとも、タイムスリップが要求され、構築されることは期待できない。しかし、IsConnected()がfalseを返した場合、端末がまだオフラインであることを確認することができます。

端末の接続の 有無が重要なタスクとは何でしょうか?私が理解する限り、インジケータはデータを視覚化するためのツールです。というデータがあります。新しいデータが届くと、ビジュアライゼーションが更新されます。データの関連性の確認は不要とすべき。これが端末の仕事です。

インジケーターの場合、サーバーとの接続を確認する必要はないと思います。履歴にあるものは描画され、履歴が読み込まれると、すべてのインジケーターバッファが再計算されることを意味します。

私のEAでは以下のような関数を開発し使用していますが、概ね満足できるもので、サーバとの接続も正しく確認できています。

bool ServerDisable(int count=10){
   if(IsTesting()||IsOptimization())return(false);
   for(int i=0;i<count;i++){
      if(IsConnected())
         if(IsTradeAllowed())
            if(!IsTradeContextBusy()){RefreshRates(); return(false);}
      Sleep(157);
   }
   Print(__FUNCTION__," Торговый сервер не отвечает");
return(true);}

具体的には、Sleep()を使って端末に制御を移し、サーバーへの接続と取引の可能性を確認します。

 
Ihor Herasko:

MT4についてです。2-3年前くらいに、Time[0]のバグをキャッチしていました。開発者はそれを修正したようですが、その後、時間が経つとまた現れるようになりました。問題は、このバグを一義的に再現することが不可能なことです。

それはあまりにも多くのトラブルではない場合、ここでトピックのトピックです - メジャーTFからの歴史の正しいダウンロードは、ここで指標です: "私はマイナーTFのバー上のメジャーTFから "MAを描画する必要があります、私は5分以内にそれを作った、それは98%のために正しく動作します、ここでこのコード2%で "落とし穴 "はバグを引き起こすでしょうか。

MT4用の正しいコードに興味があります。

#property copyright "IgorM"
#property link      "https://www.mql5.com/ru/users/igorm"
#property version   "1.00"
#property strict
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot line1
#property indicator_label1  "line1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input ENUM_TIMEFRAMES   TimeFrame   =  PERIOD_H4;
input int               MAPeriod    =  25;
//--- indicator buffers
double         BufMA[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   double cl[];
//--- indicator buffers mapping
   SetIndexBuffer(0,BufMA);
   IndicatorDigits(Digits);
// запускаем подгрузку истории и выходим, даже не проверяя подгружена она или нет, история тут еще не нужна
   CopyClose(_Symbol,TimeFrame,0,iBars(_Symbol,TimeFrame),cl);
//---
   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[])
  {
//---
   int i,limit,resultcopy;
   double closetf[];
   if(prev_calculated==0)
     {
      resultcopy=CopyClose(_Symbol,TimeFrame,0,iBars(_Symbol,TimeFrame),closetf);
      if(resultcopy<0)
        {
         Print("Подгрузка истории....");
         return(0);
        }
      if(resultcopy<MAPeriod)
        {
         Comment("Большой период МА!!!, в истории доступно ", resultcopy," баров");
         return(resultcopy);
        }
      limit=resultcopy-1;
        }else{
      resultcopy=CopyClose(_Symbol,TimeFrame,0,iBars(_Symbol,TimeFrame),closetf);
      if(resultcopy<0)
        {
         Print("Подгрузка истории....");
         return(0);
        }
      if(resultcopy<MAPeriod)
        {
         Comment("Большой период МА!!!, в истории доступно ", resultcopy," баров");
         return(resultcopy);
        }
      limit=resultcopy-prev_calculated+1;
     }
   limit = fmin(rates_total-1,limit);
// основной цикл расчета индикатора
   for(i=limit; i>=0 && !IsStopped(); i--)
     {
      BufMA[i]=iMA(_Symbol,TimeFrame,MAPeriod,0,MODE_SMA,PRICE_CLOSE,i);
     }
//---
   return(resultcopy);

  }
 
Vitaly Gorbunov:

開発者と現地の知り合いに話を聞いたのですが、一つずつ話していきますね。

1 無意味です、いつでも、どこからでもかけられます。

2 IsConnectedはコードのどこからでも呼び出すことができ、動作しますが、エラースタックに何も載せず、true/falseを返して終わりという関数です。接続手順がかなり(最低1秒)長く、ログイン時にIsConnectedが発生することを考慮すると、端末起動時に接続状態を確認し、引用フローが開始されるのを待つ必要がある。

3 これらの関数は、エラースタックに何も書き込まず、自分自身で結果を返します。

なぜ4066になったかというと、このエラーはTimeCurrent関数が原因です。端末がログインして、サーバーに時間を要求するのも、回線品質によっては時間がかかるので、クイックタイマーを用意しています。そして、TimeCurrentからのリクエストで4066を得た。そして、時刻を取得して関数が正常に動作するようになり、その関数自身がエラースタックを迂回して動作した結果、エラーを返すようになったのです。

このような場合、クイックタイマーで端末を起動し、サーバーからのデータ受信を開始したことを確認することをお勧めします。私のバリアントは少しひつこくて、OnCalculateから信号をもらってデータの受信を開始するのが正しいでしょう。

1.私の書いたものをよく読んでください。そう言ったのは初めてじゃないんですよ!どこかに電話するなとは言ってないぞ!?

iBarShift()、iTime()、SeriesInfo...()の全ての関数が TimeCurrent()を要求するということでしょうか?