English Русский 中文 Español Deutsch Português
preview
リプレイシステムの開発(第53回):物事は複雑になる(V)

リプレイシステムの開発(第53回):物事は複雑になる(V)

MetaTrader 5 | 2 12月 2024, 10:41
220 0
Daniel Jose
Daniel Jose

はじめに

前回の「リプレイシステムの開発(第52回):物事は複雑になる(IV)」では、マウス指標がコントロール指標と対話できるように新しいデータ構造体を作成しました。最初はスムーズに進んでいたやりとりも、いくつかの問題が発生し、少し変更が必要となりました。

問題の本質はコードやプラットフォーム、使用されている概念にはなく、私たちの意図と作業方法にあります。個人的には、リプレイ/シミュレーターシステムが登場するまでこの記事を読んでいた皆さんにお詫び申し上げます。正直なところ、モジュールシステムで使用されている技法の一部を使用する必要があるとは思っていませんでしたが、数十年前に開発された技術の一部を使わずにリプレイ/シミュレーターシステムの開発を続けるのは不可能だと気づきました。

ここで説明する内容は、一部の読者には非常に奇妙に思えるかもしれませんが、他の読者には非常に馴染み深いものかもしれません。それでも、どのように見ても、ここで説明するメカニズム、そしてこれからますます頻繁に使用することになるメカニズムは、MetaTrader 5内に存在し、MQL5で使用することができます。ただし、MQL5を使用する場合、チャート内またはMetaTrader 5自体内でのみ実行可能という制限があります。これは悪いことではなく、むしろ、プラットフォームはお金を扱うために設計されており、セキュリティ対策として課せられた制限です。奇妙な方法でお金を失いたくはありませんから。

したがって、この制限について文句を言う理由はありません。新人プログラマーは、ここで使用し始める内容にはしばらく戸惑うかもしれませんが、それは単に内容とその使用方法を知らないからに過ぎません。ただし、私はこれまでこの技法をしばらく使用してきましたが、これから使用し始める方法でではありません。ですから、基準を引き上げ、記事にもっと複雑な概念を適用する時が来たのだと感じています。


コンセプトの説明

プログラム間のメッセージングを多用し始めます。この分野に不慣れな方は、今から簡単な紹介があるので注意してください。はい、MQL5ではこれが可能です。正しく使用および設計されていれば、このアプローチは非常に強力です。ただし、詳細を理解していないと、完全に混乱し、MetaTrader 5で同じチャートにプログラムを一緒に配置したときに、プログラムの動作が不正確になります。

これまで、ほんれン歳で紹介したプログラムでは、プログラム間でではなくコード内でメッセージを使用して、異なるレベルにあるクラスや継承関係のないクラスでも、あるクラスが別のクラスと通信できるようにしてきました。これは、私のクラスコードを見るとわかります。ほとんどすべてのクラスコードに共通のプロシージャ、DispatchMessageがあります。このプロシージャの主な目的は、クラスに送信されたメッセージを管理することですが、他の関数を使用してクラスと通信する方法もあります。DispatchMessageは、クラス宛てのメッセージを管理するために使用されます。

このアイデアは私にとって目新しいものではありません。これは、長い間存在しており、プログラムやプロシージャ全般の間に共通のインターフェイスを作成することを目的としています。プロのプログラミングの分野で長い間働いてきた人なら、私たちが何を話しているのか分かっているでしょう。したがって、コードがまったくわからない別のプログラムにデータ、値、またはクエリを送信する必要がある場合は、この原則を使用します。非常に特定の関数にメッセージを送信すると、特定の情報が返されます。これらは、この単一の関数を通じて正確に通信します。

名前は異なる場合がありますが、提供されるデータのセットとシーケンスは常に同じです。

これは表面的でまったく意味がないと思われるかもしれませんが、プログラミング、この場合はMQL5を勉強している場合、おそらくこの関数を何度も見たことがあるでしょう。ほぼすべての指標またはエキスパートアドバイザー(EA)コードにはこの関数が含まれています。この関数、またはむしろプロシージャは、MQL5ではOnChartEventと呼ばれます。

「どうしてこんなことが可能なのか。MetaTrader 5が私のソフトウェアと通信しているということか。」と思われるかもしれません。答えは「はい」です。この呼び出し内の整数定数IDで指定された値を分析することで、MetaTrader 5が送信したメッセージをフィルタリングして判断できます。

これには非常に驚かれると思いますが、初心者にとってはすべてがさらに難しくなります。ただし、状況を複雑にしないために、MetaTrader 5のフレームワーク内で説明をおこない、それに限定します。すべてがはるかに広範で複雑です。したがって、この点をよく理解する必要があります。MetaTrader 5はプログラムにメッセージを送信します。これらのメッセージは、プログラムに存在するいくつかのプロシージャによって傍受および管理されます。これらのプロシージャの中には、より一般的で、はるかに複雑な要素を送信でき、共通の明確に定義されたインターフェイスを使用するものがあります。このプロシージャの名前はOnChartEventです。これで終わりです。次は難しい部分です。

MQL5(状況を複雑にしないために、ここではこれについてのみ説明します)では、カスタムイベントを定義できます。これらのイベントは、定数と値で示されます。この定数の名前はCHARTEVENT_CUSTOMです。したがって、この定数を使用すると、プログラムの任意のポイントからメッセージハンドラにメッセージを送信できます。これにより、特定のイベントと一般的なイベントの両方の処理を1つのポイントに集中させることができますが、いずれの場合もメッセージディスパッチャーを呼び出す必要はありません。正しい方法でおこなう必要があり、物事を簡単にするために、MQL5ではこの目的のためにEventChartCustom関数を提供しています。この関数を使用すると、デフォルトのメッセージハンドラ、前述のOnChartEvent(私の場合はDispatchMessageを呼び出します)にメッセージを送信できます。

すべては素晴らしく見え、うまく機能し、多くのことが可能になります。ただし、ここには危険が潜んでいます。私が話しているのはCHARTEVENT_CUSTOMです。これらのユーザー呼び出しの最大の危険は、私のプログラムやあなたのプログラム、または他の優れたプログラマーのプログラムにあるのではなく、ユーザーが各プログラムが何をするのかを知らないという事実にあります。多くの場合、ユーザーは実際に何が起こっているのか知りません。これが、実際に何であるかを理解せずに何かを使用しないことが重要である理由です。プログラムはいくつかのシナリオで正常に機能するかもしれませんが、プログラム間の相互作用が完全な悪夢に変わるシナリオが1つだけあります。プラットフォームがクラッシュしたり、オブジェクトが消えたり、どこからともなく現れたりして、何が起こっているのか理解できなくなる可能性があります。効果が顕著な場合は良いですが、まったく気付かれないまま発生した場合はどうでしょうか。すべてが順調に進んでいるように見えるかもしれませんが、実際には、状況は奈落の底にいるかのようです。

もしあなたがプロのプログラマーで、ソリューションを開発しているのなら、誤解しないでほしいのですが、ご自分のプログラムが他のプログラムに問題を引き起こすような方法で相互作用する可能性があること、または他のプログラムがご自分のプログラムに問題を引き起こす可能性があることをクライアントに説明する必要があります。ユーザーは、あるプログラマーのコードを別のプログラマーのコードと混在させないように注意する必要があります。これが、少し前まではWindowsが明らかな理由もなくクラッシュすることがよくあり、人々が単にプログラムのせいにしていた理由です。実際には、クラッシュは通常、同じ環境で複数のプログラムが同時に実行されているときに発生していました。

このトピックについては、この説明の主な目的から外れるため、詳しくは説明しませんが、理解しておくべき重要なことがあります。MetaTrader 5はWindowsオペレーティングシステムに似ています。適切なツールを適切な方法で使用すれば、プラットフォームで問題が発生することはありません。しかし、何でもかんでも混ぜ始めると、様々な問題が発生する可能性があるので注意が必要です。MetaTrader 5は金融市場での取引用に設計されたグラフィカル環境であることを知っていると、次の疑問が生じます。2つのプログラムがEventChartCustomを使用するとどうなるでしょうか。この関数により、MetaTrader 5はプログラマーの要求に応じてメッセージを送信します。

そうですね。この質問は非常に単純で、実際、正しい質問です。これを理解するために、より単純なケースから始めましょう。1つのプログラムがEventChartCustom関数を使用するとどうなるでしょうか。基本的に、MetaTrader 5は、OnChartEventプロシージャによって処理されるカスタムイベントを送信します。当たり前のように思えますが、実際はそうではありません。それほど明らかではなく、そこに危険が潜んでいます。

EventChartCustomの典型的な使い方は、前回の記事で示したコントロール指標のコードで見ることができます。コントロール指標のコードの30行目には、次があります。

30.     EventChartCustom(user00, C_Controls::evInit, Info.s_Infos.iPosShift, Info.df_Value, "");

MetaTrader 5がこの行を実行すると、ChartEventが表示され、チャート上に存在するコードによってOnChartEventが実行されます。これは、C_ControlクラスにあるDispatchMessage関数が見つかるまで続きます。これは、前の記事で示したコードの161行目です。便宜上、そのスニペットをここに追加しておきます。

161.            void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
162.                    {
163.                            u_Interprocess Info;
164.                            
165.                            switch (id)
166.                            {
167.                                    case CHARTEVENT_CUSTOM + C_Controls::evInit:
168.                                            Info.df_Value = dparam;
169.                                            m_Slider.Minimal = Info.s_Infos.iPosShift;
170.                                            SetPlay(Info.s_Infos.isPlay);
171.                                            if (!Info.s_Infos.isPlay) CreateCtrlSlider();
172.                                            break;

C_Controlクラスに存在するコードの一部

イベントがカスタムであるため、MetaTrader 5はOnChartEventプロシージャ呼び出しでID値を設定し、IDがCHARTEVENT_CUSTOMに対応する値に1つ追加された値になるようにします。示されているケースでは、この値はC_Control:evInitの値に対応します。しかし、C_Control:evInitの値は何でしょうか。これを知るには、C_Controlクラスのコードの35行目に行き、値をチェックする必要があります。

035.            enum EventCustom {evInit};

この値は列挙の一部です。列挙型はこの値しか持たず、初期化されていないので、デフォルト値であるNULLで始まります。すると、コントロール指標に存在する同じ行30は、実際にはMetaTrader 5によって次のように解釈されます。

30.     EventChartCustom(user00, CHARTEVENT_CUSTOM + 0, Info.s_Infos.iPosShift, Info.df_Value, "");

このコードは完璧かつ安全に動作し、C_Controlクラス内に存在するDispatchMessageプロシージャに、コンストラクタで設定されていない値を初期化させるため、プログラマーはいつでもカスタム呼び出しをおこなうことができます。このようなことはよくあることで、さまざまな場面で非常に役に立つ、完全に適切なプログラミングの形です。

マウス指標も同様です。MetaTrader 5のカスタムイベントを使用した1つのプログラム内で、別のことを理解するために今それを見てみましょう。

マウス指標のコード全体を見ても、EventChartCustomの呼び出しは1つもありません。しかし、メッセージハンドラにはカスタムイベントに応答するコードが含まれています。このコードは、将来の利用を見越してかなり長い間存在していました。この処理コードは、C_Mouseクラスの196行目と199行目にありまる。よく見ると、いくつかのことに気づくでしょう。この考えをよりよく説明するために、この記事には以下の断片を含めます。

189. virtual void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
190.                    {
191.                            int w = 0;
192.                            static double memPrice = 0;
193.                            
194.                            if (m_Mem.szShortName == NULL) switch (id)
195.                            {
196.                                    case (CHARTEVENT_CUSTOM + ev_HideMouse):
197.                                            if (m_Mem.IsFull) ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, clrNONE);
198.                                            break;
199.                                    case (CHARTEVENT_CUSTOM + ev_ShowMouse):
200.                                            if (m_Mem.IsFull) ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, m_Info.corLineH);
201.                                            break;

C_Mouseクラスに存在するコードの一部

このスニペットではev_HideMouseとev_ShowMouseを使用していることに注意してください。マウス指標の行を非表示にしたいプログラムがあれば、マウス指標にカスタムイベントを送信するようにMetaTrader 5に依頼するだけです。こうすることで、マウスラインを隠したり表示したりすることができます。オブジェクトを破壊しているのではなく、単にカラープロパティを変更しているだけであることに注意してください。

ev_HideMouseとev_ShowMouseの値は列挙型ですが、これらはどこから来たのでしょうか。C_Mouseクラスの34行目です。説明を簡単にするためにまたコードを示します。

034.            enum eEventsMouse {ev_HideMouse, ev_ShowMouse};

私が何を説明しようとしているのか、まだ理解できないかもしれません。このシステムがどのように機能するかを示した以下のビデオ01をご覧ください。


ビデオ01:デモンストレーション

すべてが完璧なハーモニーを奏で、何の問題も生じません。初期化中、コントロール指標は、カスタムイベントを処理する必要があることをMetaTrader 5に伝え、マウス指標は、マウスラインを非表示または表示するためのプログラムからのカスタムイベントを待ちます。この2つの指標を切り離しても問題は生じず、しかも互いに矛盾することもありません。しかし、一緒になると、状況はさらに複雑になります。ビデオ02をご覧ください。


ビデオ02:競合

なぜこのような現象が起こるのでしょうか。個別に動作させているときは問題ないのに、一緒に組み合わせると衝突が発生してしまうのはなぜでしょう。これは多くの初心者プログラマーにとって大きな壁となり、プログラミングに対する意欲が低い人にとっては、この段階で挫折してしまう原因にもなります。しかし、プロのプログラマーや、それを目指す人にとっては、こうした問題は学習の好機と捉えられます。彼らは知識を深め、この衝突を解消するために努力を惜しみません。こうした衝突は、異なるプログラマーが書いたプログラムを組み合わせたときや、たとえ同じプログラマーが作成したものであっても、十分なテストや創造的な検証を行わなかった場合に生じることが多いものです。さて、このような背景を理解したうえで、この問題をひとまず脇に置き、ビデオ02で取り上げている衝突の詳細に焦点を当てていきましょう。

互いに独立してうまく機能しているように見える2つの指標が、なぜこのように奇妙な形で連動するのでしょうか。


職場環境の概念を理解する

より経験豊富なユーザーであれば、すでに作業環境について聞いたことがあるか、使用したことがあるでしょう。この概念は、要素を分離して、1つのエコシステム内で独立して共存できるようにすることを基本としています。

MetaTrader 5では、この環境の問題は非常に真剣に受け止められています。この考え方を理解していないと、ビデオ02に示されている競合の理由を理解できません。最も重要なことは、この競合を解決することができないということです。覚えておいてください。マウス指標が他の指標と完全に調和して動作することを望んでいます。そのため、いくつかの問題が排除され、さらに大きなシステムのモジュールになります。

多くの人は諦めてしまうでしょうが、諦めるわけにはいきません。私たちはシステムをモジュール化しており、そのためにはマウス指標がコントロール指標と連携して動作する必要があります。

ビデオ01を見ると、指標が競合していないことがわかりますが、ビデオ02では、マウス指標とコントロール指標を同じチャートに一緒に配置したときに奇妙なことが起こります。MetaTrader 5が各チャートを他のチャートから完全に分離された環境として扱っていることがはっきりとわかります。

この種の観察は非常に重要であり、将来的にも使用されますが、ビデオ02には同様に重要な点がもう1つあります。MetaTrader 5がカスタムイベントに応答してチャートを更新し、時間枠を変更すると、いくつかのことが起こります。これを理解するには、MetaTrader 5の仕組みを知っておく必要があります。

時間枠の変更を要求すると(ビデオに示されているように)、MetaTrader 5はチャートからすべてを一時的に削除し、必要なものを復元します。このため、チャートには指標とEAのみが復元されます。プログラマーがこれを考慮していない場合、すべてのプログラムが競合します。これは、MetaTrader 5がオブジェクトを復元する順序が、ユーザーがチャートに配置した順序と一致しない可能性が高いためです。ユーザーが何も起こらないような順序ですべてをチャートに配置する可能性があります。しかし、何かが起こり、MetaTrader 5がチャートを再構築すると、順序が異なり、問題が発生する場合があります。多くの人はプラットフォームを責め、一部の人はオペレーティングシステムを責め、一部の人は神または悪魔を責めます。しかし、本当の問題は、あなたまたは他の誰かが作成したプログラムでは、複数の要素を共有できないことです。そして、多くのコードが閉じられているという事実は、競合の理由を理解することをさらに困難にします。

では、本題に戻りましょう。この記事では、マウス指標はカスタムイベントを使用しないことを説明しました。ただし、マウス指標は2つのカスタムイベントに応答します。1つはマウスが最小化されたとき、もう1つはマウスの線が表示されたときです。コントロール指標に関しては、コントロールクラスのいくつかの要素を初期化するなど、カスタムイベントを使用して応答します。

では、コードに戻りましょう。これから説明する内容に十分注意して読んでください。これを理解できれば、MetaTrader 5の仕組みを理解する大きな一歩を踏み出したことになります。

コントロール指標とマウス指標は別々にコンパイルされます。コードでは、メッセージに応答するクラスに何らかの形で関連している列挙体を使用します。ただし、このような推論は、依然としていくつかの仮定をおこなっていることを意味し、プログラミングでは仮定をおこなうべきではありません。コンパイラにとって、このカスタムイベントコードは常に定数からシフトされた値になります。定数はCHARTEVENT_CUSTOMであり、列挙体は既定値(ゼロ)から始まるため、マウス指標とコントロール指標のメッセージを処理するコードは両方とも同じインデックス(CHARTEVENT_CUSTOMプラスゼロ)から始まります。

これでは競合の理由が説明されないと思うかもしれませんが、それは間違いです。これで理由が説明されます。それ以上です。さらに、MetaTrader 5の作業環境がどのように構成されているかも説明されます。

各チャートはMetaTrader 5の作業環境を表しています。プログラムがカスタムイベントをMetaTrader 5に送信すると、そのイベントはプログラムや他の特定のプログラムには送信されず、MetaTrader 5に送信されます。プラットフォームは、作業環境、つまりチャート上に存在するすべてのプログラムに対してこのイベントを発生させます。ビデオ02では、これがどのように発生するかを確認できます。これは、チャート内のすべてのプログラムが、カスタムイベントがトリガーされるとすぐに、MetaTrader 5から同じ通知を受信するためです。次に、カスタムイベントを使用してポジションを開いたり閉じたりするEAについて考えてみましょう。同じイベントが、EAと同じチャートにある指標でシグナルを送信するイベントと同じインデックスを使用する場合、EAまたは指標がカスタムイベントをトリガーするとどうなるでしょうか。大きな問題に直面することになります。 

段階的に説明しようと思います。問題は見た目よりはるかに複雑で、この同じシステムを他の目的にも利用します。だからこそ、何が起こっているかを理解する必要があります。理解しないと、崖で終わる路地に迷い込んでしまいます。

おそらく、この問題の解決策はないのだろうかと自問しているのではないでしょうか。解決策はあります。しかも、ある程度の知識は必要ですが、非常に簡単です。ただし、この記事では、この段階では複雑すぎるいくつかの点を説明し、いくつかの変更を加える必要があるため、これについては詳しく説明しません。


結論

この記事では、次の記事で取り上げるトピックの準備として、概要を説明しました。このトピックが非常に複雑であり、多くの人にとってすぐに理解するのが難しいことは承知しています。しかし、今回の記事で学習の第一歩を踏み出すことが重要です。次回の記事では、このテーマにおける主要な問題について深掘りしていきます。

今回の内容をより深く理解するためには、カスタムイベントを生成して応答するシンプルな指標など、小規模なプログラムを自作することをおすすめします。それらを1つのチャートに配置した場合と、複数のチャートに分けた場合の動作を観察してみてください。特に重要なのは、同じチャート内と異なるチャート間の両方で、1つの指標が別の指標に何らかの変更を加える仕組みを試してみることです。

もし、異なるチャート間でカスタムイベントを介した相互作用がうまくいかなくても、心配しないでください。それはあなたが未熟なプログラマーという意味ではありません。ただ、まだ必要な知識を得ていないだけかもしれません。この記事では、その方法を具体的に示すことはしませんが、次の記事でさらに詳しく説明し、理解を深める手助けをします。ここでお気づきかもしれませんが、私はMQL5の持つ制約を補うために外部DLLの使用を避けるよう心がけています。これまでのところ、MQL5だけで複雑なソリューションを必要とせずに目的を達成できているためです。

それでは、学習を続けてください。次の記事でお会いしましょう。これから直面する厳しい課題に備え、引き続き努力してください。

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

添付されたファイル |
Anexo.zip (420.65 KB)
チャート上で取引を視覚化する(第2回):データのグラフ表示 チャート上で取引を視覚化する(第2回):データのグラフ表示
ここでは、取引エントリを分析するために取引の印刷画面のアンロードを簡素化するスクリプトをゼロから開発します。単一の取引に関するすべての必要な情報は、異なる時間枠を描画する機能を備えた1つのチャートに便利に表示されます。
リプレイシステムの開発(第52回):物事は複雑になる(IV) リプレイシステムの開発(第52回):物事は複雑になる(IV)
この記事では、信頼性と安定性のある操作を確保するために、マウスポインタを変更してコントロール指標との対話を有効にします。
初心者からエキスパートへ:MQL5での共同デバッグ 初心者からエキスパートへ:MQL5での共同デバッグ
問題解決は、MQL5でのプログラミングのような複雑なスキルを習得するための簡潔なルーチンを確立することができます。このアプローチでは、問題解決に集中しながら、同時にスキルアップを図ることができます。問題に取り組めば取り組むほど、高度な専門知識が脳に伝達されます。個人的には、デバッグはプログラミングをマスターするための最も効果的な方法だと思っています。今日は、コードクリーニングのプロセスを紹介し、乱雑なプログラムをクリーンで機能的なものに変えるための最善のテクニックについて解説します。この記事を読んで、貴重な洞察を発見してください。
PythonとMQL5による多銘柄分析(前編):NASDAQ集積回路メーカー PythonとMQL5による多銘柄分析(前編):NASDAQ集積回路メーカー
ポートフォリオのリターンを最大化するために、AIを活用してポジションサイジングと注文数量を最適化する方法について解説します。本稿では、アルゴリズムを用いて最適なポートフォリオを特定し、期待リターンやリスク許容度に応じてポートフォリオを調整する手法を紹介します。このプロセスでは、SciPyライブラリやMQL5言語を活用し、保有中のすべてのデータを基に、最適かつ分散化されたポートフォリオを構築します。