記事"MQL5 でのアサーション"についてのディスカッション - ページ 3

 
説明する。MQL5でこの記事を書いている時点では、プログラムが緊急停止するメカニズムはなかった。代替案としてruntime error 、プログラムがクラッシュすることが保証されていた。
それは真実ではない。EAはExpertRemove()で、インジケータはChartIndicatorDelete()で停止でき、スクリプトにとっては些細なことです。
 
Alain Verleyen:
そんなことはありません。EAはExpertRemove()で、インジケータはChartIndicatorDelete()で停止できます。

シクルでExpertRemove()で終了する方法を例示してください。

例えば、次のようなコードです:

#property version   "1.00"
#property strict

int OnInit()
  {
   for(int i = 0; i < 100; i++)
   {
      if(i == 2)
      {
         ExpertRemove();
      }
      Print(i);
   }
      
//---
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {

      
  }

void OnTick()
  {
//---
   
  }

i==2の場合に終了し、他のステップは実行されない必要があります。ジャーナルには "0 "と "1 "だけを表示しなければなりません。この関数で どのようにそれを行うことができますか?

今現在、ExpertRemove() は必要な瞬間にEAを停止するのではなく、すべてのステップが実行され、その後にEAが停止されます。しかし、これはアサーションメカニズムとしては間違っています。EAのどの部分に対しても普遍的なマクロや関数が必要だからです。


インジケーターについて - インジケーターのShortNameを定義する普遍的なメカニズムを教えてください。このメカニズムがなければ、アサーションにこの関数を使用することができないからです。はい、具体的なインジケーターでShortNameを定義することはできます(例えば、多くの人がやっているように、グローバル変数で定義することができます。ですから、ChartIndicatorDelete()で普遍的なメカニズム(つまり、assert(...)という1行を追加するだけで、あらゆるインジケータに対応できるマクロや関数)を作ることはできないのです。


そして、コードのどの部分に対しても、スクリプトの「些細な」バリエーションを示してください。スクリプトのどの部分に対しても、1つの(!)関数またはマクロでなければなりません:

1) ciclesの場合
2) 任意の戻り値を持つ関数の場合
3) 戻り値を持たない関数(void)の場合。

というわけで、スクリプトのどの部分にも、このように「assert(...)」という行を1行追加するだけでよいのです:

#property version   "1.00"
#property strict

void OnStart()
  {
   assert(...);

  }

double SomeDouble()
  {
   assert(...);
   return 0.0;
  }

color SomeColor()
  {
   assert(...);
   return clrNONE;
  }

string SomeString()
  {
   assert(...);
   return "";
  }

void SomeVoid()
  {
   assert(...);
   return;
  }

void SomeCicle()
  {
   while(!IsStopped())
     {
      assert(...);
     }
  }

P.S. 英語が下手でごめんなさい。

 

または、ExpertRemove() を使用した EA の他の例。)

例えば、出来高が必要以上に大きくなったらアプリを停止させなければ なりません(これは単なる例であり、実際の状況ではこの状況を別の方法で処理する必要があります):

#property version   "1.00"
#property strict

int OnInit()
  {
   OpenTrade();
//---
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {

      
  }

void OnTick()
  {
//---
   
  }
bool OpenTrade()
{
   double volume = GetVolume();
   
   if(volume > 1)
   {
      Print("Volume > 1, stop EA!");
      ExpertRemove();
   }
   
   Print("Opening position ...");
   
   return true;
}

double GetVolume()
{
   return 999.0;
}

コードの必要な場所で瞬間的にEAを停止させなければなりません(これはアサーションの 意味です)。しかし、この場合のExpertRemove()は正しいバリアントではありません:

2015.12.06 10:53:22.253 Test EURUSD,H1: Volume > 1, stop EA!<br/ translate="no">2015.12.06 10:53:22.253 Test EURUSD,H1: ExpertRemove function called
2015.12.06 10:53:22.253 Test EURUSD,H1: Opening position ...


そこで、ExpertRemove()関数(returnやbreakなどを使用せず、コードのどの部分に対しても普遍的でなければならない)をこの天井に使用する方法を教えてください。

 
Sergey Eremin:

シクルでExpertRemove()を使用して終了する方法の例を教えてください。

例えば、こんなコードがあります:

i == 2 の場合に終了する必要があります。ジャーナルには "0 "と "1 "だけを表示しなければなりません。この関数でどのようにそれを行うことができますか?

今現在、ExpertRemove() は必要な瞬間にEAを停止するのではなく、すべてのステップが実行され、その後にEAが停止されます。しかし、これはアサーションメカニズムとしては間違っています。なぜなら、どのEAのどの部分に対しても普遍的なマクロや関数が必要だからです。

OnInit()の中でExpertRemove()を使う 必要はなく、return(INIT_FAILED)を使えばいいのです;

int OnInit()
  {
//---
    ...

         if(somethign wrong)
           {
            //ExpertRemove(); 
            return(INIT_FAILED);    //--- OnInit() で ExpertRemove() を使用する必要はない。
           }
    ...
  }

を返すだけです:

            ExpertRemove();
            return;           //--- 現在のイベント・ハンドラを終了するには、returnを返すだけだ。

or

            ExpertRemove();
            return(x);        //--- 現在のイベント・ハンドラを終了するには、returnを返すだけだ。

インジケータについて - インジケータの ShortName を定義する普遍的なメカニズムを教えてください。このメカニズムがないと、アサーションにこの関数を使用できないからです。たしかに、具体的なインジケータでShortNameを定義することはできますが(たとえば、多くの人がやっているように、グローバル変数を使って)、たとえば普遍的な関数「GetShortName()」はありません。そのため、ChartIndicatorDelete()を使って、普遍的なメカニズム(つまり、「assert(...)」という1行を追加するだけで、あらゆるインジケータに対応できるマクロや関数)を作ることはできません。

何が問題なのでしょうか?あなたは自分のインジケーターで作業しており、それはあなたのコードなので、短い名前を知っています。

私の投稿は、プログラムを即座に終了させる方法がないと言っているのは正しくないと言いたかったのです。あなたのアサーション・プロジェクトの解決策を見つけるのはあなた自身です。

インジケータでグローバル変数を使うのは、決して悪いやり方ではありません。もちろん、「これは悪い習慣だ」と自己主張し、新たな制限を作ろうとすれば、不可能なことがたくさん出てくるでしょう。

そして、スクリプトの「些細な」バリアントを、コードのどの部分でもいいから示してください。スクリプトのどの部分に対しても、1つの(!)関数かマクロでなければなりません:

1) ciclesの場合
2) 任意の戻り値を持つ関数の場合
3) 戻り値を持たない関数(void)の場合。

つまり、スクリプトのどの部分にも、このように「assert(...)」という行を1行追加するだけでいいのです:

EAの場合と同じだ。

ファイル:
 
Alain Verleyen:

私の投稿は、プログラムを即座に終了させる方法がないと言っているのは正しくないと言いたかったのです。あなたのアサーション・プロジェクトで解決策を見つけるのはあなた自身です。

インジケータでグローバル変数を使うのは、決して悪いやり方ではありません。もちろん、このような「悪い習慣である」というアサーションで自分自身で新しい制限を作ろうとすれば、不可能なことがたくさん見つかるでしょう。

わかりました。ありがとう。

しかし、私の記事で言いたいのはアサーションに対する解決策だ。コードのどの場所(OnInitやciclesを含む)でもMQL4/5アプリを停止させる普遍的な メカニズムだ。どの 部分でも1行 追加するだけで完了だ。多くのプラグイン言語のアサーション・メカニズムで機能するようにね。)

はい、その通りです。しかし、私の考えるアサーションは、コードのどの 部分に対しても 普遍的なソリューションではない。

EAの例をありがとう。

 
Sergey Eremin:

分かったよ。ありがとう。

しかし、私の記事で言いたいのは、アサーションに関する解決策だ。コードのどの場所(OnInitやciclesを含む)でもMQL4/5アプリを停止させる普遍的な 仕組みだ。どの 部分でも1行 追加するだけで完了だ。多くのプラグイン言語のアサーション・メカニズムで機能するようにね。)

はい、その通りです。しかし、私の考えるアサーションは、コードのどの 部分に対しても 普遍的なソリューションではない。

EAの例をありがとう。

私はあなたが何をしたいのか知っているし、それは完全に可能だ。

マクロの呼び出しコンテキストを分析し、それがEAかインジケータかを検出し、__FUNCSIG__を解析 します。

それを普遍的なメカニズムにするかどうかはあなた次第です。

 
Alain Verleyen:

私はあなたが何をしたいのか知っていますし、それは完全に可能です。

マクロの呼び出しコンテキストを分析し、それがEAかインジケータかを検出し、__FUNCSIG__を解析します。

それを普遍的なメカニズムにするかどうかはあなた次第です。

ええ、最初はそんなことを考えていたのですが、最終的には記事にあるような形にしました :)

コメントありがとうございました!

 

もし誰かがこのコードを使おうとするなら、次の点に注意してほしい。

   if(true)
      assert(1==1, "")
   else
      Print("Never executed");

は、elseブランチからの「実行されませんでした」というメッセージにつながる。

assertを 正しく使うためには、たとえばこのように修正する必要があります:

#define  assert(condition, message) \
       do if(!(condition)) \
        { \
         string fullMessage= \
                            #condition+", " \
                            +__FILE__+", " \
                            +__FUNCSIG__+", " \
                            +"line: "+(string)__LINE__ \
                            +(message=="" ? "" : ", "+message); \
         \
         Alert("Assertion failed! "+fullMessage); \
         double x[]; \
         ArrayResize(x, 0); \
         x[1] = 0.0; \
        } while(false)
#else
#define  assert(condition, message) 
#endif

(#elseブランチのマクロも修正します:"; "の代わりに空文字列を返します)。

この変形では、assert(...)の後に"; "を置くべきである。