ライブラリ: MT5 用の高速 iBarShift と Bars

 

MT5 用の高速 iBarShift と Bars:

MQL4 の Bars と iBarShift に似た完全かつ高速関数です。


作者: Nikolai Semko

 

MT5 のビルド 1847 以降、Bars 関数で ハングするバグが修正されました。また、標準の iBarShift 関数も追加されました。
したがって、これらの関数のパフォーマンスを上げるには(10 倍のどこか)、このコードバリアントを使用する方がよいでしょう:

int fBars(string symbol_name,ENUM_TIMEFRAMES  timeframe,datetime start_time,datetime stop_time)
  {
   static string LastSymb=NULL;
   static ENUM_TIMEFRAMES LastTimeFrame=0;
   static datetime LastTime=0;
   static datetime LastTime0=0;
   static int PerSec=0;
   static int PreBars=0;
   static datetime LastBAR=0;
   static datetime LastTimeCur=0;
   static bool flag=true;
   static int max_bars=TerminalInfoInteger(TERMINAL_MAXBARS);
   datetime TimeCur;
   if(timeframe==0) timeframe=_Period;
   const bool changeTF=LastTimeFrame!=timeframe;
   const bool changeSymb=LastSymb!=symbol_name;
   const bool change=changeTF || changeSymb || flag;

   LastTimeFrame=timeframe; LastSymb=symbol_name;
   if(changeTF) PerSec=::PeriodSeconds(timeframe); if(PerSec==0) { flag=true; return(0);}

   if(stop_time<start_time)
     {
      TimeCur=stop_time;
      stop_time=start_time;
      start_time=TimeCur;
     }
   if(changeSymb)
     {
      if(!SymbolInfoInteger(symbol_name,SYMBOL_SELECT))
        {
         SymbolSelect(symbol_name,true);
         ChartRedraw();
        }
     }
   TimeCur=TimeCurrent();
   if(timeframe==PERIOD_W1) TimeCur-=(TimeCur+345600)%PerSec; // 1970年01月01日-木曜日。マイナス4日。
   if(timeframe<PERIOD_W1) TimeCur-=TimeCur%PerSec;
   if(start_time>TimeCur) { flag=true; return(0);}
   if(timeframe==PERIOD_MN1)
     {
      MqlDateTime dt;
      TimeToStruct(TimeCur,dt);
      TimeCur=dt.year*12+dt.mon;
     }

   if(changeTF || changeSymb || TimeCur!=LastTimeCur)
      LastBAR=(datetime)SeriesInfoInteger(symbol_name,timeframe,SERIES_LASTBAR_DATE);

   LastTimeCur=TimeCur;
   if(start_time>LastBAR) { flag=true; return(0);}

   datetime tS,tF=0;
   if(timeframe==PERIOD_W1) tS=start_time-(start_time+345599)%PerSec-1;
   else if(timeframe<PERIOD_MN1) tS=start_time-(start_time-1)%PerSec-1;
   else  // PERIOD_MN1
     {
      MqlDateTime dt;
      TimeToStruct(start_time-1,dt);
      tS=dt.year*12+dt.mon;
     }
   if(stop_time<=LastBAR)
     {
      if(timeframe<PERIOD_W1) tF=stop_time-(stop_time)%PerSec;
      else if(timeframe==PERIOD_W1) tF=stop_time-(stop_time+345600)%PerSec;
      else // PERIOD_MN1
        {
         MqlDateTime dt0;
         TimeToStruct(stop_time-1,dt0);
         tF=dt0.year*12+dt0.mon;
        }
     }
   if(change || tS!=LastTime || tF!=LastTime0)
     { PreBars=Bars(symbol_name,timeframe,start_time,stop_time); LastTime=tS; LastTime0=tF; }
   flag=false;
   return(PreBars);
  }


int fBarShift(string symb,ENUM_TIMEFRAMES TimeFrame,datetime time,bool exact=false)
  {
   int Res=fBars(symb,TimeFrame,time+1,UINT_MAX);
   if(exact) if((TimeFrame!=PERIOD_MN1 || time>TimeCurrent()) && Res==fBars(symb,TimeFrame,time-PeriodSeconds(TimeFrame)+1,UINT_MAX)) return(-1);
   return(Res);
  }
ファイル:
iBars.mqh  14 kb
 
Nikolai Semko:

ビルド 1847 から、MT5 のBars 関数で ハングするバグが修正されました。また、標準の iBarShift 関数も追加されました。
したがって、これらの関数のパフォーマンスを向上させるには(10 倍のどこか) 、このコードバリアントを使用することをお勧めします:

コードを servesk に送り、プラットフォームに標準実装してもらう。

 
Vitaly Muzichenko:

そのコードをservicedkに送り、プラットフォームに標準実装してもらう。


このコードはクロスプラットフォームです。そして、最も興味深いことは、MT4ではゲインがないので、Bars関数は MT4で最適に書かれているということです。

 
Nikolai Semko:


このコードはクロスプラットフォームである。そして面白いのは、MT4ではゲインがないので、Bars関数が MT4で最適に書かれていることです。

このスレッドは フォローされている。あなたの投稿をポケット経由で挿入します。

Альтернативные реализации стандартных функций/подходов
Альтернативные реализации стандартных функций/подходов
  • 2016.09.01
  • www.mql5.com
NormalizeDouble Результат 1123275 и 1666643 в пользу MyNormalizeDouble (Optimize=1). Без оптимизации - быстрее раза в четыре (на память...
 
fxsaber:

このスレッドは 監視されています。ポケットから投稿してください。

わかりました。しかし、なぜかポケットからではうまくいかない。うまくいかない。リンクからです。

 
Nikolai Semko:

したがって、これらの関数の速度を上げる(10倍程度)には、このコードバリアントを使用するのがよい:

特に、あなたのコードには膨大な種類のチェックが含まれていることを考えるとね。 その本質に触れるのは億劫だが、このような混乱が高速に機能するとは信じがたい。

 
Alexey Navoykov:

スピードについて過剰反応しすぎでは? 特に、あなたのコードにある膨大な数のあらゆる種類のチェックを考えるとね。 その本質に踏み込むのは億劫だが、こんなゴタゴタが速く動くとは信じがたい。

このメッセージを書くには、あまりに怠惰であるほうがいい。))

私はスピードテストのために、特にこれらの関数にインジケータを取り付けました。

Bars関数はマイクロ秒単位で実行され、チェック、算術演算(2進数の平方根計算でさえ)はナノ秒未満で実行される:

void OnStart()
  {
   ulong t;
   double sum=0;
   t=GetMicrosecondCount();
   for (double i=1; i<2;i+=0.000001 ) sum+=sqrt(i);
   t=GetMicrosecondCount()-t;
   Print(「1,000,000の根の和=" + DoubleToString(sum,18)+ " を " + IntegerToString((int)t) + 「マイクロ秒); 
  }


2018.06.14 19:23:31.188 SpeedSQRT (EURUSD,M4)   Сумма 1 000 000 корней = 1218952.6235881459433586 за 1990 микросекунд
2018.06.14 19:26:30.814 SpeedSQRT (EURUSD,M4)   Сумма 1 000 000 корней = 1218952.6235881459433586 за 1946 микросекунд
2018.06.14 19:26:34.188 SpeedSQRT (EURUSD,M4)   Сумма 1 000 000 корней = 1218952.6235881459433586 за 1946 микросекунд
2018.06.14 19:26:36.344 SpeedSQRT (EURUSD,M4)   Сумма 1 000 000 корней = 1218952.6235881459433586 за 1973 микросекунд

このスピードテストから、2進数の根の和を計算する100万サイクルが2000マイクロ秒で実行されることがわかる。
つまり、1サイクルは2ナノ秒で実行される。1サイクルは1チェック、2進数の和2回、2進数の平方根の計算1回です。

ファイル:
 
Nikolai Semko:

この記事を書くのは、よっぽど怠け者の方がいい。))

これらの機能には特にスピードテストインジケーターを付けた。

Bars関数はマイクロ秒で実行され、チェックや算術演算(2進数の平方根の計算でさえ)はナノ秒以下だ:

このスピードテストから、2進数の根の和を計算する100万サイクルは2000マイクロ秒で実行されることがわかる。
つまり、1サイクルは2ナノ秒で実行される。1サイクルは1チェック、2進数の和2回、2進数の平方根の計算1回である。

まだ新しいビルドを入れていないので、再現できません。私は、あなたの関数が特殊なケースに最適化されていると理解しています。 シンボルは変化せず、タイムフレームも変化しないなどです。 そのため、Bars関数がそこで一度だけ呼び出されるのでしょう。 そして、シンボルもタイムフレームも愚かにも定数として設定されています。 そのため、コンパイラが関数全体を最適化し、不要なものをすべて捨てている可能性が高いのです。

要するに、テストが間違っているのだ。 シンボルの配列とピリオドの配列があるはずで、それらすべてに対して関数を実行すべきだ。 そうすれば、何かについて話すことができる。

 
Alexey Navoykov:

まだ新しいビルドをインストールしていないので、再現できません。シンボルは変化せず、タイムフレームも変化しないなど、特殊なケースに対して関数が最適化されていると理解しています。 そのため、Bars関数は一度だけ呼び出されます。 シンボルもタイムフレームも定数として設定されています。 そのため、コンパイラが関数全体を最適化し、不要なものをすべて捨てている可能性があります。

要するに、テストが誤って実行されているのだ。 文字の配列とピリオドの配列があるはずだ。 あなたの関数をそれらすべてに通すべきだ。 そうすれば、何かについて話すことができる。

シンボルは変化せず、タイムフレームも変化しない」というのは、どれも特別なケースではない!


もちろん、その通りです。バーがコールされるたびにTFやシンボルが変更されるのであれば、標準的なものの方が早く機能します。この場合、静的変数を TFの数と同じサイズの静的変数の配列に置き換えるだけでよいのですが。しかし、私はこれを特殊なケースだと考えている。しかし、この特殊なケースの解決策は、必要であれば生きる権利がある。おそらく、このようなケースのためにコードを修正することは意味があるだろう。А ...それがおそらくあなたが言っていたことでしょう。

そして定数についてですが、お気づきいただきありがとうございます。元の関数のパラメータは定数ではないので修正しました。スピードに関しては何も変わっていません。

 
Nikolai Semko:

そのようなインジケーターや、TF やシンボルを常に変更する Expert Advisor をたくさんお持ちですか。

私はポートフォリオ分析とポートフォリオ・トレーディングに重点を置いています。 しかし、大規模な計算となると、配列を扱うiBarShiftは 不適切です。 実際、iBarShiftや他の類似の関数はまれな呼び出しのためのものです。CopyTimeで配列を取得して、すぐにすべてを見つけることができます。 だから、このテスト例は実際の練習ではほとんど役に立たないのです。 コーダーがダミーでない限り)そして、ダミーのために悩む必要はないと思います。)

関数をクラスにラップする方が論理的だと思います。 そうすれば、呼び出すたびにシンボルや周期をチェックする必要がなくなります。 時系列ごとに別々のオブジェクトを持つことになります。