English Русский 中文 Español Deutsch Português
Expert Advisor Code で簡単にエラーを検出しリカバリする方法

Expert Advisor Code で簡単にエラーを検出しリカバリする方法

MetaTrader 4トレーディングシステム | 16 3月 2016, 08:16
1 984 0
Roman Kramar
Roman Kramar

はじめに

MQL4 l言語でトレーディング EA を作成することは、いくつかの側面の視点からは簡単なことではありません。

  • まず、多かれ少なかれむつかしいトレーディングシステムのアルゴリズム作成自体がすでに問題です。というのも、EA のアルゴリズム作成の特異性から、特定の MetaTrader 4 環境に至るまで多くの細かい事柄に配慮する必要があるためです。
  • 次に、のち に EA アルゴリズムができたとしても、作成済みアルゴリズムをプログラム言語である MQL4 に変換する際発生する問題がなくなるわけではないのです。

トレーディングプラットフォーム MetaTrader 4 に合わせて調整する必要があるのです。-トレーディングを書くためのプログラム言語の存在は以前に有効であった代替と比べるとすでに大きな前進ではあります。コンパイラは正しい EA を書くためにひじょうに役立ちます。「コンパイルする」をクリックするとすぐに、コード内になる構文エラーをすべてレポートしてくれますインタプリタ型言語を扱う場合、そのようなエラーは EA の動作中にしか見つからず、そのため問題が増え、作成期間が長引くことになるでしょう。構文エラー以外、EA には論理エラーがあります。ここではそのようなエラーを取り上げます。



組み込み関数使用時のエラー

組み込み関数を使用しなければトレーディング EA は何もできないので、そのような関数が返すエラーの分析が楽になるようにします。まず、トレーディング処理に直接連携している関数動作結果を見ます。それは、そのような関数のエラーを無視すると EA の効果がきわどくなるためです。のちに別の組み込み関数についてもお話しします。

残念ながら、MQL4 オプションを使用することで、可能性あるエラー状況をすべて処理する一般的ライブラリを書くことはできません。個別ケースではエラーを別で処理する必要があります。ですが、良い点もあります。エラーをすべて処理する必要はないということです。エラーの多くは EA 作成段階で排除されるものです。ただこのためには、よいタイミングでそういったエラーが検出されることです。例として MQL4 における EA の典型的なエラーを考察します。

1)エラー130- ERR_INVALID_STOPS
2) エラー 146 -ERR_TRADE_CONTEXT_BUSY

前者のエラーが発生する際の一つには、市場に近づけすぎて EA が未決注文を出そうとすることです。その存在はなんらかの場合に EA の特性を著しく損なう可能性があります。たとえば、収益性あるポジションを開いている場合、EA が150ポイントごとで利益を減らすとします。次の試行でエラー130 が発生し、価格が前のストップレベルに戻れば、これは正当な利益を奪うこととなります。価格とストップの間に許容できる最小の距離を考慮する関数を EA コードに挿入することで、そのような可能性にもかかわらず、このエラーは一番最初に排除されます。

後者のエラー「トレードコンテキストが混みあっています」は完全に排除することができません。1件のターミナルで複数が動作する際、この状況に出くわします。Expert Advisor の一つがポジションをオープンしようとしているとき、もう一つが同じことをしようとする場合です。結果としてこのエラーはかならず処理される必要があります。

よって EA 動作中に組み込み関数がエラーを返しているか、つねに知る必要があります。それは以下の簡単な関数を追加することで行えます。

#include <stderror.mqh>
#include <stdlib.mqh>
 
void logError(string functionName, string msg, int errorCode = -1)
  {
    Print("ERROR: in " + functionName + "()");
    Print("ERROR: " + msg );
    
    int err = GetLastError();
    if(errorCode != -1) 
        err = errorCode;
        
    if(err != ERR_NO_ERROR)
      {
        Print("ERROR: code=" + err + " - " + ErrorDescription( err ));
      }    
  }

もっともシンプルな場合では、以下のように使用されます。


void openLongTrade()
  {
    int ticket = OrderSend(Symbol(), OP_BUY, 1.0, Ask + 5, 5, 0, 0);
    if(ticket == -1) 
        logError("openLongTrade", "could not open order");
  }

関数 logError() の1番目のパラメータは関数名を表しています。そこでエラーが検出されるのです。この場合、それは関数openLongTrade() です。われわれの Expert Advisor が関数 OrderSend() を複数個所で呼び出す場合、どの場合にエラーが発生するか正確に判断する機会があります。2番目のパラメータはエラー説明を渡します。正確に関数 openLongTrade 内のどの箇所でエラーが検出されたかわかるようになります。これは短い記述の場合と、組み込み関数内に渡されるパラメータすべての値を含む詳しい記述の場合があります。

私は最後のバリアントを好みます。なぜならエラーが出現すると、すぐに分析に必要な全情報を入手することができるからです。OrderSend() を呼び出す前に現在価格が最後にわかっている価格から大きく変動したとします。その結果、エラーが発生し、EA ログファイルんは以下の行が表示されます。

 エラー:openLongTrade() 内
 エラー:オーダーをオープンできませんでした。
 エラー:コード=138 -再クオート

すなわち、以下が明確です。

  1. エラーがどの関数に発生したか。
  2. 何を参照するか(ここの場合、ポジションオープンの試行です)。
  3. 正確にどのエラーが発生したか(エラーコードとその説明)。

ここから関数 logError() の3番目のオプションであるパラメータを考察します。特定のエラータイプを処理したければ、そしてその他のエラーがログファイルに入っていれば、前のようにそれが必要です。

void updateStopLoss(double newStopLoss)
  {
    bool modified = OrderModify(OrderTicket(), OrderOpenPrice(), 
                newStopLoss, OrderTakeProfit(), OrderExpiration());
    
    if(!modified)
      {
        int errorCode = GetLastError();
        if(errorCode != ERR_NO_RESULT )
            logError("updateStopLoss", "failed to modify order", errorCode);
      }
  }

関数updateStopLoss() 内で組み込み関数 OrderModify() が呼ばれます。この関数はエラー処理の点では OrderSend() と大きく異なります。変更済みオーダーのパラメータが現在のパラメータとまったく変わらなければ、関数はエラー ERR_NO_RESULT を返します。その状況が EA によって受け入れられるなら、このエラーは無視します。このためには、GetLastError() によって返される値を分析します。コード ERR_NO_RESULT のエラーが発生する場合、ログファイルには何も書き込みません。

ただし、別のエラーが発生すると、以前にしたと同じようにそれを報告する必要があります。このためには、関数 GetLastError() の結果を中間媒介変数に保存し、3番目のパラメータによってそれを関数 logError() に渡します。実際、組み込み関数 GetLastError() はそれが呼び出された後に最後のエラーを自動的にゼロ設定します。エラーコードを logError() に渡さなければ、EA ログファイルのエラーはコード0、『エラーなし』となります。

たとえば再クオートなど、その他エラーの処理の際も同様の処理が行われます。ポイントとしては処理の必要なエラーのみ処理し、その他は関数logError() に渡すのです。この場合、EA 動作中に予想外のエラーが起こったかどうか知ることになります。ログファイル分析後、このエラーが個別の処理を必要とするかどうか、EA コードを改良するとき消すことができるかわかります。そのような方法でやりやすく、バグ修正にかかる時間を短縮することになります。



論理エラーの診断

Expert Advisor の論理エラーも十分厄介なものです。EA にステップスルー オプションがないことでそのようなエラーをなくすことはひじょうに不快なタスクです。現時点でそのようなエラーを診断するための主なツールは組み込み関数 Print() です。それによって重要な変数の現在値を表示し、EA の動作フローを記録することができます。可視化を伴う検証中に EA をデバッグすると、組み込み関数 Comment() もまた役に立ちます。結果、EA の誤った動作が確認されると、関数 Print() の一時的呼び出しを追加し、発生するエラーの想定箇所における EA の内部状態を記録します。

むつかしいエラー状況を検出するには、関数 Print() の診断呼び出しを何十と追加する必要があることもあります。そして問題が検出され、リカバリの後、関数呼び出しは削除されるかコメントを付けて EA lのログファイルに負荷をかけすぎて検証スピードを落とさないようにします。EA コードがすでに異なる状態を定期定期にレコードするために、関数 Print() を持っていると状況はさらに悪くなります。一時的 Print() 関数呼出しは 'Print' という EA コードの簡単な検索では検出できません。関数を削除するかしないかについて考える必要があります。

たとえば、関数 OrderSend()、OrderModify()、OrderClose() のエラーを記録する際、変数「ビッド」と「アスク」の現在値をログファイルに表示すると便利です。これにより、のようなエラー ERR_INVALID_STOPS や ERR_OFF_QUOTES 検索理由が簡単になります。

この診断情報をログファイルに書き込むには、以下の追加関数を使用することをお薦めします。

void logInfo(string msg)
  {
    Print("INFO: " + msg);
  }

その理由は以下です。

  • 第1に、検索中、その関数は 'Print' と混同しない。
  • 第2に、この関数にはもう一つ特殊な点がありますが、それはのちにお話します。

関数 Print() の一時的な診断呼び出しを追加、削除するには時間がかかります。もう一つ別の方法を提案するのはそのためです。それはコード内で論理エラーを検出するのに効率的で、時間節約になります。以下の簡単な関数を分析します。

void openLongTrade(double stopLoss)
  {
    int ticket = OrderSend(Symbol(), OP_BUY, 1.0, Ask, 5, stopLoss, 0);
    if(ticket == -1) 
        logError("openLongTrade", "could not open order");
  }

この場合、ロングポジションをオープンするとき、正しい EA 動作では、パラメータ、ストップロスの値は現在のビッド価格以上にはなりません。すなわち、関数openLongTrade() を呼び出す際の表記を修正します。条件、ストップロス<ビッド が常に満たされるようにするのです。分析される関数を書く段階ですでにそれは解っているので、以下のような方法でそれを使います。


void openLongTrade( double stopLoss )
  {
    assert("openLongTrade", stopLoss < Bid, "stopLoss < Bid");
    
    int ticket = OrderSend(Symbol(), OP_BUY, 1.0, Ask, 5, stopLoss, 0);
    if(ticket == -1) 
        logError("openLongTrade", "could not open order");
  }

すなわち、新規の追加関数 assert() によってコードに記述を挿入します。関数自体はひじょうにシンプルです。


void assert(string functionName, bool assertion, string description = "")
  {
    if(!assertion) 
        Print("ASSERT: in " + functionName + "() - " + description);
  }

関数の最初のパラメータは関数名で、そこで条件が確認されます(関数 logError() の類似体によって)2番目のパラメータはこの条件確認の結果を示します。そして3番目のパラメータはその表記です。結果、機体の条件が満たされなければ、EA のログファイルには以下の情報が入ります。

  1. 条件が満たされていない関数名
  2. この条件の記述

記述として、たとえば、条件そのもの、または、エラー原因をつきとめるのに役立つのであれば、条件確認時に制御される変数値を持つより詳しい説明を表示することができます。

もちろん、提供されている例は最大限単純にされたものです。考え方をはっきり表しているとよいと思います。EA の機能性が高まるにつれ、それがどのように動作するか、どの条件や入力パラメータが受け取り可能かどれが不可か明確にわかります。関数 assert() によってそれを EA コードに挿入することで、EA の動作ロジックが破たんしている箇所に関する有用な情報を入手します。また、関数 Print() の一時的呼び出しを追加、削除する必要を部分的になくします。それは関数 assert() は期待条件との不一致が検出される場合のみ EA のログファイルに診断メッセージを作成するためです。

もう一つ便利な方法はこの関数を各除算処理前に使用することです。実際何だかんだと論理エラーはゼロ除算につながることがあるのです。そのような場合、Expert Advisor は動作を停止し、ログファイルには「ゼロ除算」という1行が表示されます。徐sな処理がコード内で多数行われる場合は、エラー発生個所を検出することはかなりむつかしくなります。ここで関数 assert() がひじょうに役立つのです。除算処理前に対応するチェックを挿入するだけです。

assert("buildChannel", distance > 0, "distance > 0");
double slope = delta / distance;

そしてゼロ除算の場合、ログファイルを全部見て、エラーの正確な発生個所を見つけるのです。



エラー検出目的での EA ログファイル分析

提案されたエラー検出用関数はログファイル内でエラーを簡単に検出するのに役立ちます。テキストモードでログファイルを開き、語『エラー』と『アサート』で検索するだけです。ただ作成中、組み込み関数の呼出し結果を何かと省略する、という状況に出会うことがあります。ゼロ除算が見落とされることがあるのです。ポジションのオープン、クローズ、変更などを含む何千行の中でそのようなエラーに関するメッセージを検出するにはどうすればよいのでしょうか?そのような問題に出会う場合、以下の解決法をお薦めします。

Microsoft Excel を開き、CSV ファイルとして EA 処理ログファイルをダウンロードします。それを分離子として指定し、スペースを1つまたは複数使用します。ここで『オートフィルタ―』を有効にします。これは隣り合う2列(どの列かは簡単にわかります)でフィルターオプションをくまなく調べ、ログファイルにエラーがあるか、ターミナルによって書き込まれたか否か知る便利な機会を提供します。関数 logInfo()、logError()、assert() によって作成されるエントリはすべて接頭辞("INFO:"、"ERROR:"、"ASSERT:")で始まります。エラーに関するターミナルのエントリも、オーダーを処理することに関する一般的なエントリのバリアントいくつかの中で簡単にみられます。

このタスクはより洗練された方法で行うことができます。たとえば、テキストファイルを処理するツールの知識があれば、EA の動作エラーを表す EA のログファイル行のみ表示する短いスクリプトを書きます。私は、長い期間でのテスターで各 Expert Advisor を実行し、説明した方法で動作のログファイルを分析することを強くお薦めします。 これでデモアカウントで EA を実行する前に大半の潜在的エラーを検出することができます。その後、動作ログファイルを同じように時々分析すると、リアルタイムのアカウントでのみ EA 動作特有のそのときのエラーを検出するのに役立ちます。



おわりに

説明した追加関数とシンプルな方法によって、エラー検出手順とプログラム言語 MQL4 で書かれたEA コード内でのリカバリを簡素化することができます。みなさんの便宜のために、上述の関数は添付ファイルに入っています。#includeディレクトリによってみなさんの EA にファイルを追加するだけです。説明した方法が、Expert Advisor の堅牢性と正確性を懸念されるトレーダーのみなさんにうまく活用いただけることを願っています。


MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1473

添付されたファイル |
debug.mqh (1.07 KB)
外為市場は予測可能なのか?自分独自のトレーディング戦略を作成する方法は? 外為市場は予測可能なのか?自分独自のトレーディング戦略を作成する方法は?
Forex を始める人は皆こういった疑問に答えようとします。しかし、だれもがその答えを見つけるとは限りません。何年も賢明に働き、研究したとしても、です。本項のその他多くの疑問と共に、私は個人的にこの質問に答えてきました。そういう答えの結果として、効率的なトレーディング戦略の作成する方法が決まったのです。
FOREX におけるクラスターインディケータの実用的な応用 FOREX におけるクラスターインディケータの実用的な応用
クラスターインディケータは通貨ペアを個別の通貨に分けるインディケータのセットです。インディケータにより、相対的通貨変動を追跡し、潜在的な新しい通貨トレンド形成を判断し、トレードシグナルを受信し、中長期ポジションをフォローすることができます。
人気のトレーディングシステムを基にした Expert Advisors と売買ロボット最適化の錬金術(パート2) 人気のトレーディングシステムを基にした Expert Advisors と売買ロボット最適化の錬金術(パート2)
本稿では、もっともシンプルなトレーディングシステム実装アルゴリズムの分析を続け、最適化結果を用いていくつか関連する詳細を説明します。本稿は初心者トレーダーや EA プログラマーを対象としています。
ピボットポイント分析に基づくトレーディング戦略 ピボットポイント分析に基づくトレーディング戦略
「ピボットポイント(PP)」分析は日次で変動の激しい市場に対するもっともシンプルで効率的な戦略です。それはコンピュータがまだない時代にすでに利用されていました。そのころ、株式で働くトレーダーはフレームや計数機で数える以外にADP 機器は何も使えませんでした。