English Русский 中文 Español Deutsch Português
preview
リプレイシステムの開発(第38回):道を切り開く(II)

リプレイシステムの開発(第38回):道を切り開く(II)

MetaTrader 5 | 17 6月 2024, 16:03
169 0
Daniel Jose
Daniel Jose

はじめに

前回の「リプレイシステムの開発(第37回):道を切り開く(I)」稿では、チャート上で指標の重複を防ぐ簡単な方法を見てきました。この記事では、わずか数行からなる非常にシンプルなコードで、MetaTrader 5プラットフォームが、1つのコピーで2番目の指標が必要な場合に、チャート上に2番目の指標が表示されないようにしてくれることを確認しました。指標を重複させないことは重要です。

そのアイデアと、望ましい結果がどのように達成されたかを理解していただければ幸いです。どのような場合でも、指標は重複してはなりません。

MetaTrader 5の重複禁止の原則を確認しながらも、指標とEAの双方向通信はまだ先の話であることに注意してください。まだこれにはほど遠いです。ただし、指標がチャート上で重複しないという保証は、少なくとも安心感を与えてくれます。なぜなら、指標とEAが相互作用すれば、正しい指標を扱っていることがわかるからです。

この記事では、EAの目を通して物事を見ていくことにしますが、指標にも変更を加える必要があります。前回の記事にあった指標は、残念ながらEAにまったく反応しないからです。これはEAが何かを知りたがっているときに起こります。


プロセス間の最初の相互作用を作成する

何が起こっているのかをきちんと説明するためには、いくつかのコントロールポイントを作成する必要があります。指標のコードから始めましょう。ご心配なく。すべて簡単に理解できます。

完全な指標コードは以下の通りです。

01. #property copyright "Daniel Jose"
02. #property link      ""
03. #property version   "1.00"
04. #property indicator_chart_window
05. #property indicator_plots 0
06. //+------------------------------------------------------------------+
07. #define def_ShortName       "SWAP MSG"
08. #define def_ShortNameTmp    def_ShortName + "_Tmp"
09. //+------------------------------------------------------------------+
10. input double user00 = 0.0;
11. //+------------------------------------------------------------------+
12. long m_id;
13. //+------------------------------------------------------------------+
14. int OnInit()
15. {
16.     m_id = ChartID();
17.     IndicatorSetString(INDICATOR_SHORTNAME, def_ShortNameTmp);
18.     if (ChartWindowFind(m_id, def_ShortName) != -1)
19.     {
20.             ChartIndicatorDelete(m_id, 0, def_ShortNameTmp);
21.             Print("Only one instance is allowed...");
22.             return INIT_FAILED;
23.     }
24.     IndicatorSetString(INDICATOR_SHORTNAME, def_ShortName);
25.     Print("Indicator configured with the following value:", user00);
26.     
27.     return INIT_SUCCEEDED;
28. }
29. //+------------------------------------------------------------------+
30. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
31. {
32.     return rates_total;
33. }
34. //+------------------------------------------------------------------+


コードに追加されたのは25行目だけです。これが、少なくとも最初の検証ラインとなります。現時点で興味があるのは、EAが指標とどのように相互作用するのか、そして指標に情報やデータを送信できるかです。

10行目では、指標が期待する情報の型はdoubleです。あえてそうしているのは、EAと指標間のコミュニケーションにおいて、グローバル端末変数システムに取って代わるメカニズムを作成することが目的であるためです。開発または使用した手段が不適切であることが判明した場合、このモデルは端末グローバル変数のモデルに簡単に置き換えることができます。

また、少なくともEAから指標へのデータ転送には、他の型のデータを使用して通信を提供することもできます。

指標のコードを変更したので、EAのコードに移ります。以下にそのすべてを掲載します。

01. #property copyright "Daniel Jose"
02. #property link      ""
03. #property version   "1.00"
04. //+------------------------------------------------------------------+
05. input double user00 = 2.0;
06. //+------------------------------------------------------------------+
07. int m_handle;
08. long m_id;
09. //+------------------------------------------------------------------+
10. int OnInit()
11. {
12.     m_id = ChartID();
13.     if ((m_handle = ChartIndicatorGet(m_id, 0, "SWAP MSG")) == INVALID_HANDLE)
14.     {
15.             m_handle = iCustom(NULL, PERIOD_CURRENT, "Mode Swap\\Swap MSG.ex5", user00);
16.             ChartIndicatorAdd(m_id, 0, m_handle);
17.     }
18.     Print("Indicator loading result:", m_handle != INVALID_HANDLE ? "Success" : "Failed");
19.     
20.     return INIT_SUCCEEDED;
21. }
22. //+------------------------------------------------------------------+
23. void OnDeinit(const int reason)
24. {
25.     ChartIndicatorDelete(m_id, 0, "SWAP MSG");
26.     IndicatorRelease(m_handle);
27. }
28. //+------------------------------------------------------------------+
29. void OnTick()
30. {
31. }
32. //+------------------------------------------------------------------+


多くの人にとって、このEAコードは非常に奇妙に思えるかもしれません。その動作について説明します。これは私たちが本当にしなければならないことの第一歩です。

5行目では、指標に渡された値を設定する機会をユーザーに与えます。覚えておいてほしいのは、コミュニケーションがどのようにおこなわれるかをテストし、理解したいということです。7行目と8行目には、EAコードの2つの内部グローバル変数が含まれています。私は通常、グローバル変数の使用は好みませんが、この場合は例外とします。これらの変数の内容は10行目で始まる、OnInitコマンドを処理するコードで決定されます。

少し複雑に見えるかもしれません。この段階で理解しておかなければならないことがいくつかあるからです。

12行目では、EAが稼働している時間枠のインデックスを示す変数を初期化しています。そして、初心者がよく問題にぶつかる13行目が来ます。多くの人はこの行をコードに追加しません。この行がなくてもすぐにコードが壊れるわけではありませんが、この行があることによって、ある種のエラーの発生を防ぐことができます。これらのエラーの多くはいつでも発生する可能性がある実行時エラーであり、解決が困難です。

13行目にコードを追加したことで、MetaTrader 5がチャート上に必要な指標をすでに持っている場合、その指標はハンドルを返します。したがって、わざわざ指標をチャート上に配置する必要はありません。

ただし、13行目で目的の指標がチャートに表示されていない場合は、指標をチャートに追加するコードを実行します。私たちが必要とし、これから使用する指標はカスタム指標です。そこで、15行目にあるiCustomを呼び出します。

厄介なのは、15行目にあるiCustomがなぜこのように宣言されているのか、ということです。おわかりでしょうか。これを理解するために、ドキュメントに書かれていることを見てみましょう。

int  iCustom(
                 string            symbol,   // symbol name
                 ENUM_TIMEFRAMES   period,   // period
                 string            name      // folder/custom indicator name
                 ...                         // list of indicator parameters
             );

上の表から、関数の最初のパラメータが銘柄名であることがわかりますが、コードの15行目では、最初のパラメータがNULLです。なぜでしょう。なぜ_Symbol定数を使わなかったのでしょうか。その理由は、コンパイラにとってNULL_Symbolは同じものだからです。こうすることで、EAチャートが持つ銘柄と同じ銘柄を使用して指標が作成されます。

リストの次のパラメータはチャート期間です。今回もまた、多くの人が期待しているものとは違うものがあります。15行目でPERIOD_CURRENTを使用していますが、なぜでしょうか。その理由は、指標をEAと同じ期間に同期させたいということです(詳細:指標を別のチャート期間で分析したい場合は、このパラメータに希望の期間を指定するだけです)。このように、指標は一定の期間に固定され、EAは異なる期間を移動することができます。

カスタム指標に関して言えば、深刻な結果を招きかねないのは3番目のパラメータだと私は考えています。多くの人はここに何を書けばいいのかわからず、意味を理解していないために空欄にしたり、間違った場所を指定したりすることがあります。間違った場所を指定すると、MetaTrader 5は必要な指標を見つけることができません。

15行目の3番目のパラメータで宣言されている内容を見てください。名前だけでなく、名前とパスも指定します。この情報はどこから来るのでしょうか。それを知るためには、前回の記事に戻り、この情報がどこから来たものなのかを調べる必要があります。図01を参照してください。

図01

図01:指標の作成

図01では、3番目のパラメータの情報がどこから来ているかがわかります。これらは実質的に同じことですが、次を変更します。まず、ルートディレクトリを削除します。 この場合、Indicatorsです。これは、MetaTrader 5が最初にこのディレクトリ内の指標を探すからです。2番目のポイントは.ex5ファイルを追加したことです。こうすることで、実行ファイルの正しい場所を得ることができます。MetaTrader 5がEAをチャート上に配置し、15行目を実行すると、どこでどの指標を使用すべきかがわかります。

以下では、起こりうる問題や課題について見ていきますが、その前に基本的なことを整理しておきましょう。

この3番目のパラメータとそれに続くパラメータはオプションです。指標に何らかの値を与えたい場合は、4番目のパラメータからおこなう必要があります。ただし、パラメータが指標に表示される順序と同じ順序で表示されるようにする必要があります。また、正しい型であることも確認する必要があります。指標がfloatまたはlong値の受信を期待している場合、double を入力することはできません。入力した場合、MetaTrader 5は指標を起動した直後にエラーを生成します。

指標にパラメータを渡す方法は他にもありますが、ここではわかりやすくするためにiCustomを使用します。指標のコードを見ると、10行目でdouble値が期待されていることがわかります。この値は、EAコードの15行目の第4パラメータで、EAを通じて指標に提供されます。

ここで、多くの人がおろそかにしている、システム全体の問題につながる重要な問題が出てきます。EAコードの16行目です。なぜこの行が重要なのでしょうか。

カスタム指標に関しては、この行を無視できる場合があります。これは特に、MetaTrader 5がチャート上に配置された1つのインスタンスのみをサポートしたい場合に必要となる指標に当てはまります。どのような形であれ、16行目を無視することはできないし、16行目がある場合は25行目も追加しなければなりません。

この2行は問題を回避します。16行目はチャート上で指標を実行します。したがって、ユーザーが同じチャート上で指標の別のインスタンスを実行しようとすると、MetaTrader 5と指標コードが新しいインスタンスの実行を阻止します。EAのコードから16行目を削除すると、ユーザーが誤ってチャート上に指標の新しいインスタンスを配置してしまい、EAではなくユーザーが指標が実行する計算について混乱してしまう可能性があります。

計算された指標の場合、一定の問題がありますが、Chart Traderのような指標の場合、問題はさらに複雑になります。この場合、グラフィックオブジェクトを扱っているので、何事も正しいやり方を理解することが大切です。そうすれば、より複雑なことをする方法を理解しやすくなります。

16行目がいかに重要か、これではっきりしたと思います。25行目は何をしているかと言えば、指定した指標をチャートから削除しています。削除する指標の名前を指定する必要があります。これは、指標コードの24行目の指標に配置されています。名前が同じでないと、MetaTrader 5はどの指標を削除するべきなのか理解できません。さらに、場合によっては、どのサブウインドウが使用されるかを伝える必要もあります。サブウィンドウを使用し、この値はゼロの使われるままにしておきます。

そして26行目で、指標ハンドラはもう必要ないので削除します。

このEAと指標の相互作用のスキームで、MetaTrader 5がどのように機能するかを見てみましょう。これを理解するには、いくつかのことをする必要があります。したがって、プロセスの細部に細心の注意を払ってください。また、各変更がMetaTrader 5に独自の処理方法をもたらすため、各変更をテストし、生成されたコードを試す必要があります。上記の説明を読むだけでなく、何が起きているのかを理解することが重要です。EAがある方法で書かれたとき、あるいは同じEAが異なる方法でプログラムされたときに何が起こるかを理解するためには、3つの状況を考える必要があります。EAと指標で使用されているコードは、これまで説明してきたものと同じで、違いはEAのコード行の有無だけです。

次のようにします。

  • まず、すべての行でコードをコンパイルし、MetaTrader 5でシステムがどのように動作するかを確認します。
  • 次に16行目と25行目を削除し、MetaTrader 5でシステムを再テストします。
  • 最後に、16行目のみを削除して25行目を残し、その後、もう一度システムをテストします。

こんなことはナンセンスで、経験豊富なプログラマーである自分がそんなミスをするはずがないと思われるかもしれませんが、MetaTrader 5を実行する際に、各コード行が何をおこない、どのような結果をもたらすかを知ることは、おそらく見た目以上に重要です。

この段階までくれば、グローバル端末変数を使わずにEAから指標にデータを転送する第二段階を理解したことになります。読者は優れたプログラマーになるための大きな一歩を踏み出したのです。ただし、理解できなくても、がっかりしないでください。この記事か前回の記事の最初に戻って、このステップを理解するようにしましょう。今、物事は非常に複雑になっています。指標がEAにデータを送信するようにする必要があります。

ここで指標はEAにデータを送信します。場合によっては、これは非常に簡単なことですが、私の記事を読んでくださっている方なら、私が物事を極端な方向に持っていき、コンピューターに汗をかかせ、違うことをするように求めるのが好きだということにお気づきでしょう。なぜなら、私は言語とプラットフォームの両方が、可能なことの限界で機能することを望んでいるからです。


IndicatorCreateとiCustomのどちらを使用するべか

多くの初心者は、カスタム指標をどのように呼び出すのか疑問に思うかもしれません。これは2つの方法でおこなうことができます。iCustomの使用法については、前回のトピックで説明しました。別の方法もあり、一部のタイプのモデル化ではその方法の方が魅力的ですが、他のタイプのモデル化ではiCustomを使用するだけで十分です。

これは、どちらかの方法を使用しなければならないという話ではありません。ここでの目的は、IndicatorCreateを呼び出して独自の指標を読み込めるようにする方法を示すことです。

その前に、ひとつ理解しておきましょう。IndicatorCreate関数は特別な関数ではありません。これは実は基本関数です。これは何を意味するのでしょうか。基本関数とは、基本的に他の関数を促進する役割を果たす関数ですが、1つだけ細かい点があります。「派生」関数は基本関数を使用しますが、より使用しやすくするものです。

これは、基本関数に期待されるような、呼び出しをモデル化する必要がないからです。もっとシンプルなモデル化を使えばいいのです。こうして他の関数が生まれます。テクニカル指標ドキュメントでご覧ください。これらの指標のうち、iCustomは基本的にモデル化を単純化する派生機能です。

では、iCustomの代わりにIndicatorCreateを使用した場合、冒頭で説明したEAのソースコードはどうなるのでしょうか。そのコードを以下に示します。

01. #property copyright "Daniel Jose"
02. #property link      ""
03. #property version   "1.00"
04. //+------------------------------------------------------------------+
05. input double user00 = 2.2;
06. //+------------------------------------------------------------------+
07. int m_handle;
08. long m_id;
09. //+------------------------------------------------------------------+
10. int OnInit()
11. {
12.     MqlParam params[];
13.     
14.     m_id = ChartID();       
15.     if ((m_handle = ChartIndicatorGet(m_id, 0, "SWAP MSG")) == INVALID_HANDLE)
16.     {
17.             ArrayResize(params, 2);
18.             params[0].type = TYPE_STRING;
19.             params[0].string_value = "Mode Swap\\SWAP MSG";
20.             params[1].type = TYPE_DOUBLE;
21.             params[1].double_value = user00;
22.             m_handle = IndicatorCreate(NULL, PERIOD_CURRENT, IND_CUSTOM, ArraySize(params), params);
23.             ChartIndicatorAdd(m_id, 0, m_handle);
24.     }
25.     Print("Indicator loading result:", m_handle != INVALID_HANDLE ? "Success" : "Failed");
26.     
27.     return INIT_SUCCEEDED;
28. }
29. //+------------------------------------------------------------------+
30. void OnDeinit(const int reason)
31. {
32.     ChartIndicatorDelete(m_id, 0, "SWAP MSG");
33.     IndicatorRelease(m_handle);
34. }
35. //+------------------------------------------------------------------+
36. void OnTick()
37. {
38. }
39. //+------------------------------------------------------------------+

上のコードと冒頭で示したコードの違いを比べてみてください。どちらも同じことをします。主な疑問は、IndicatorCreateの呼び出しを使用するこのコードがなぜこのように実行される必要があるのかということです。

iCustom関数には、私たちが何をする必要があるのかが隠されています。

まず、変数を宣言する必要があります。これは12行目で配列として宣言されています。これはまさにこの方法でおこなうべきです。チャート上に指標が存在しない場合は、指標を作成する必要があります。そのためには、IndicatorCreate関数に何をどのようにおこなうかを指示しなければなりません。

指標で使用するパラメータの数に加え、IndicatorCreate関数に指標の名前を伝えなければなりません。したがって、指標の名前だけを入力するのであれば、17行目のArrayResize関数は2つの要素を選択するのではなく、1つの要素を選択しなければなりません。もし指標に5つのパラメータを渡せば、6つの要素を割り当てなければならない、などです。送信するパラメータの数を確認し、追加のポジションを割り当てましょう。

次に、この配列を設定する必要があります。22行目のIndicatorCreate関数は、カスタム指標を使用することを示しています。これはIND_CUSTOM列挙を使用しておこなわれます。やらなければならないことがいくつかあります。18行目では、配列の最初の位置の処理方法を示しています。MQL5はC++に近いので、ゼロから数え始めることを覚えておいてください。最初の位置の情報タイプはSTRINGでなければならないので、宣言は18行目のように記述します。

19行目に、使用するカスタム指標の名前を入力します。指標名は、iCustomの呼び出しを使用する場合と同じであることに注意してください。唯一の違いは、ファイルの拡張子を指定しないことです。これは拡張子.ex5の実行可能ファイルでなければならないので、拡張子の指定は任意です。

重要:18行目と19行目でおこなっていることは、カスタム指標が使用されるたびにおこなわなければなりません。他の指標を使用する場合は、それが何であれ、配列データの設定を始めるとすぐに、パラメータを指定する必要があります。これは20行目から始まります。

IndicatorCreate関数に使用するカスタム指標を指定したので、関数に渡すパラメータの入力を始めましょう。これらのパラメータは正しい順序で指定されなければなりません。どの指標を使用するにせよ、間違った型を宣言すると実行時エラーになります。したがって、この情報を記入する際には細心の注意を払ってください。

20行目では、最初のパラメータをdouble型に指定していますが、ENUM_DATATYPE列挙で定義されている型であれば、どれでも構いません。どれを使用してもいいですが、いくつか注意すべき点があります。

TYPE_DOUBLETYPE_FLOATの2つの型がdouble_valueに使用されます。この場合、21行目です。

もし20行目でTYPE_STRING型が使用されていれば、21行目で値はstring_value型変数にキャストされます。20行目で宣言されたその他の型については、21行目でinteger_value変数を使用します。

これは非常に重要なことなので、この情報を明確にしておきましょう。下の表をご覧ください。

使用される識別子 データ型 値の配置先 

TYPE_BOOL  boolean integer_value

TYPE_CHAR  char integer_value    
TYPE_UCHAR    unsigned Char integer_value    
TYPE_SHORT    short integer_value    
TYPE_USHORT    unsigned Short integer_value
   
TYPE_COLOUR    color integer_value
   
TYPE_INT    integer integer_value
   
TYPE_UINT    unsigned Integer integer_value
   
TYPE_DATETIME    dateTime integer_value
   
TYPE_LONG    long integer_value      
TYPE_ULONG    unsigned Long integer_value
   
TYPE_FLOAT    float double_value     
TYPE_DOUBLE    double double_value
   
TYPE_STRING    string string_value    

対応表

この表は、20行目で何を使用するか(使用される識別子)と、21行目でどの変数が値を受け取るかを明確に示しています。これは、カスタム指標に渡される各パラメータに対しておこなう必要があります。使用するパラメータは1つだけなので、その1つだけを扱うことにします。

ここでの特定の場合では、IndicatorCreate呼び出しの使用は、その派生であるiCustomよりも手間がかかることに注意してください。

定義したいパラメータをすべて設定したら、22行目に進み、実際に関数を呼び出します。これは、物事を簡単に増減できるようにするためです。すべてのフィールドが入力されているので、指標やパラメータの数を変更する必要があっても、22行目を編集する必要はありません。

アイデアは、物事を複雑にするのではなく、常にシンプルにすることです。

MetaTrader 5で同じタイプの実行を設定するためにこの余分な作業があるため、現在のコードでIndicatorCreate関数が使用されることはあまりありませんが、それを使用することを妨げるものは何もありません。

この記事を終える前に、もう1つの関数について簡単に触れておきたいと思います。IndicatorParametersです。この関数は、未知の指標について何かを確認することができます。チャート上に複数の異なる指標があり、それぞれが特定の方法で初期化されているとします。指標を使用した戦略を自動化したいと思うかもしれませんが、相場は突然変化するので、すべての指標を正しく設定するのに数分かかるかもしれません。

このプロセスを少しスピードアップするには、IndicatorParameters関数を使用します。この関数が呼び出されると、MetaTrader 5は、特定の指標がどのように設定されているかを正確に伝えるために、この関数を入力します。次に、別の関数(通常はIndicatorCreate)を使用して、この指標の設定を変更します。EAがこの指標を使用して売買する場合、トリガーがあるため、EAはすぐに何をすべきかを理解します。

この問題については、取引の自動化に関する連載自動で動くEAを作成する(第15回):自動化(VII)」稿で売買のトリガーとして指標を使用する方法を検討し、詳しく説明して実証しました。

今述べたように、IndicatorParameters関数を使えば、同じEAをさらに面白くすることができます。ただし、IndicatorParameters関数の使用法については、少なくともこのリプレイシミュレーションの連載では触れません。ただ、この関数がいかに便利かを言及したかったのです。


結論

この記事では、指標にデータを送信する方法を見てきました。今回はEAを使用しましたが、スクリプトなど他のタイプのプロセスを使用することもできます。残念ながら、少なくともこの記事を書いている時点では、サービスの性質上、この作業をする方法としてサービスを使用することはできません。

でも、大丈夫です。今あるものでやっていくしかありません。ただし、この疑問はまだ完全に解決されたわけではありません。指標からEAにデータを転送する方法を理解する必要があります。リプレイ/シミュレーションシステムでChartTraderを使用する方法が必要ですが、そのためにグローバル端末変数を使用したくないし、複数のプログラムをコンパイルして、どれかをコンパイルし忘れるリスクも避けたいのです。

ChartTraderに必要なものにどれだけ近づいているかを知るには、別の記事が必要でしょう。そこで、次回の記事では、ChartTraderを作成するために必要なアプローチを理解しましょう。

次回の記事もお見逃しなく。テーマはとても興味深く、エキサイティングなものになるでしょう。

MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/11591

添付されたファイル |
EA.mq5 (1.36 KB)
swap.mq5 (1.31 KB)
母集団最適化アルゴリズム:2進数遺伝的アルゴリズム(BGA)(第2回) 母集団最適化アルゴリズム:2進数遺伝的アルゴリズム(BGA)(第2回)
この記事では、自然界の生物の遺伝物質で起こる自然なプロセスをモデル化した2進数遺伝的アルゴリズム(binary genetic algorithm:BGA)を見ていきます。
母集団最適化アルゴリズム:2進数遺伝的アルゴリズム(BGA)(第1回) 母集団最適化アルゴリズム:2進数遺伝的アルゴリズム(BGA)(第1回)
この記事では、2進数遺伝的アルゴリズムやその他の集団アルゴリズムで使用されるさまざまな手法を探ります。選択、交叉、突然変異といったアルゴリズムの主な構成要素と、それらが最適化に与える影響について見ていきます。さらに、データの表示手法と、それが最適化結果に与える影響についても研究します。
RestAPIを統合したMQL5強化学習エージェントの開発(第3回):MQL5で自動手番とテストスクリプトを作成する RestAPIを統合したMQL5強化学習エージェントの開発(第3回):MQL5で自動手番とテストスクリプトを作成する
この記事では、MQL5関数とユニットテストを統合した、Pythonによる三目並べの自動手番の実装について説明します。目標は、MQL5でのテストを通じて、対戦のインタラクティブ性を向上させ、システムの信頼性を確保することです。このプレゼンテーションでは、対戦ロジックの開発、統合、実地テストについて説明し、最後にダイナミックな対戦環境と堅牢な統合システムを作成します。
ニューラルネットワークが簡単に(第71回):目標条件付き予測符号化(GCPC) ニューラルネットワークが簡単に(第71回):目標条件付き予測符号化(GCPC)
前回の記事では、Decision Transformer法と、そこから派生したいくつかのアルゴリズムについて説明しました。さまざまな目標設定手法で実験しました。実験では、さまざまな方法で目標を設定しましたが、それ以前に通過した軌跡に関するモデルの研究は、常に私たちの関心の外にありました。この記事では、このギャップを埋める手法を紹介したいと思います。