English Русский 中文 Español Deutsch Português
preview
リプレイシステムの開発(第28回):エキスパートアドバイザープロジェクト-C_Mouseクラス(II)

リプレイシステムの開発(第28回):エキスパートアドバイザープロジェクト-C_Mouseクラス(II)

MetaTrader 5テスター | 30 3月 2024, 15:14
248 0
Daniel Jose
Daniel Jose

はじめに

前回の「リプレイシステムの開発(第27回):エキスパートアドバイザープロジェクト(II)」稿では、新しいクラスの開発に着手しました。しかし、記事の最後の方では、プログラミングに対する別のアプローチを提示することの重要性を確信しました。これは、自然言語に近づくための好奇心のためだけでしょう。

プログラミングの経験が長い人にとっては、以下に示すことはあまり意味がないかもしれません。プログラミングを自然言語に近づけるために、なぜこんな苦労をするのでしょうか。答えは簡単で、マシンのためにプログラミングしているのではなく、他のプログラマーのためにプログラミングしているからです。何かを因数分解することができる最初のシステムが登場した時点では、エンジニアがどれだけプロジェクトを熟知しているかにすべてがかかっていました。これが、プログラミング用の端末がなかったコンピュータ技術の黎明期の現実でした。

それが発展し、より多くの人々が何かを創造できることに興味を持つようになると、新しいアイデアやプログラミングの方法が現れ、以前のようなコネクタの位置を変えるスタイルに取って変わりました。最初の端末が登場したのはこの時です。そのうちに、もともとバイナリ形式だけでおこなわれていたプログラミングは、もはや主流ではなくなりました。プログラムの進化が非常に早く、プログラムされたものをより効率的に読み取る方法を見つける必要性に迫られたからです。その頃、アセンブリ言語が登場しました。この強力なフレームワークは、複雑なバイナリコード作業を、OpCodesまたはニーモニックコードという形で、より読みやすいものに変換しました。プログラムはますます複雑になり、より多くのコードを必要とするようになり、最初の高水準言語が登場しました。

より自然に近い言語が使用できるようになったため、OpCodeを直接扱う必要がなくなりました。当初、これらの言語は主に数学的概念を作成し、記述するために開発されました。つまり、数式をコンピュータで読み取り可能な形式に変換することを容易にするためのものでした。このプロセスは、もはや人が手作業でおこなう必要はありませんでした。これにより、新しい、コンパイラの時代が生まれました。コンパイラは人間の言語を機械が理解できる言語に翻訳します。プログラムがどのように作られるかを説明し、より多くの人に学んでもらい、自分のアイデアをコンピューターが理解できるものに変換してもらおうと、私は何年もこの方法でプログラミングをしてきました。しかし、プログラミングは、作りたいものを表現するために記号を組み合わせたり使ったりすることがほとんどなので、多くの人がいくつかの概念を理解するのが難しいことに気づきました。

ただし、MQL5言語がC/C++に似ていて、読みやすくなるようにコーディングする能力を持っていることを考えれば、何か違うことを実証するのに理想的になります。そして、いろいろなことを分析した結果、コードを完全に理解しなくても、愛好家が何がプログラムされているかを理解する手助けができることに気づきました。そこで、コードの表現方法を変えることにしました。結局のところ、すべてはコンパイラによって理解されるので、コンパイラにとってはどうでもいいことです。しかし、これは愛好家にとっては非常に重要なことです。一見すると奇妙で変わったコードに見えるかもしれませんが、初心者にとってははるかに理解しやすいでしょう。

MQL5という言語を、より自然言語に近い形で使用するこの短い時間に、ぜひご参加ください。


Defines.mqhファイルの作成

2回前の記事で、コンパイル指示文#defineの使い方を見ました。ファイルの最後で定義が削除されない特殊なケースがあることは述べましたが、正しい方法がなかったため、このディレクティブの使い方の実用化はその時には示しませんでした。そのため、この質問は未解決としました。ここで重要なのは、MQL5がC/C++から派生した言語であることを理解した上で、MQL5に関するいくつかの事柄や概念を理解すれば、その言語である程度の操作を問題なくおこなえるようになるということです。こうすることで、これらの記号をすべて理解できないノンプログラマーにとっても、何がおこなわれているかを理解する必要のあるプログラマーにとっても、コードが読みやすくなります。

その方法の1つが、#defineディレクティブを使用してコードを読みやすくすることです。ただし、いくつかの制限があります。一見すると非常に奇妙に思えるかもしれませんが、すべてはMQL5言語の構文に存在するいくつかの記号や記号の組み合わせを、誇張することなく正しく定義する方法を知っているかどうかにかかっています。新しい言語を作るわけではありません。既存の記号をかなり一貫した方法で置き換えているだけです。こうしてDefines.mqhファイルが誕生します。それまで記号的だった構文が、人間の読者にとってより表現しやすい言葉や定義に変わる定義が含まれています。

以下は、このファイルの全内容です。

//+------------------------------------------------------------------+
#property copyright "Daniel Jose"
/*+------------------------------------------------------------------+
Definitions for increasing the level of the coded language in MQL5, for
more details see the article at the following link:
https://www.mql5.com/ja/articles/11349
+------------------------------------------------------------------+*/
#define equal =
#define different !=
#define identical ==
#define and &&
//+------------------------------------------------------------------+

事実上、何の機能も果たさないこの小さなコードは、実際には何をしているのでしょうか。これを理解するには、実際に使用してみる必要があります。それぞれのコード行は、コードをより読みやすくするための追加を表しています。経験の少ない人でも、プログラミングのすべてではないにせよ、いくつかの側面は理解できるでしょう。コードの読みやすさは常に改善しなければならない点です。たとえ前準備の作業が多少増えたとしても、より読みやすいコードを作る方がいいです。しかし、最終的にはそれだけの価値があります。なぜなら、誰も、作者でさえアクセスできない象形文字のようなコードを扱いたいとは思わないからです。そして、このコードの書き方が失われてしまえば、その言語や人が存在しなくなることで、そこに含まれる知識もすべて失われてしまいます。

コードを読みやすくする方法の1つに、コメントを使用することがあります。しかし、私の記事のコードを見ると、コメントをしていないことに気づくでしょう。というのも、私の考えでは、このようなコードは非常にシンプルで完全に読みやすいからです。記事の説明がなくても、これらのコードを理解できますか。まさにここがポイントです。ある時点で、コードは非常に複雑になり、適切な構造がなければまったく読めなくなります。そして私ですらそれを維持し改善することはできないでしょう。

Defines.mqhファイルを作成したら、コンパイラにそれを使わせる必要があります。そのために、システム全体を構築するための最も基本的なファイルの1つであるC_Terminal.mqhにこのファイルをインクルードします。インクルードされたC_Terminal.mqhの部分には以下の行があります。

#include "Macros.mqh"
#include "..\..\Defines.mqh"

これは非常に重要なことなのでご注意ください。Macros.mqhファイルを二重引用符で囲んで宣言し、このファイルがC_Terminal.mqhファイルと同じフォルダにあることをコンパイラに伝えます。しかし、Defines.mqhファイルをインクルードすると、これも二重引用符で囲まれますが、1つの特定の機能があります。この違いは..\にあります。これは、C_Terminal.mqhがあるディレクトリから始めて、Defines.mqhファイルを見つけるためにディレクトリ構造を何階層上へ行けばよいかをコンパイラに指示します。この場合、ディレクトリ構造に異なるコードレベルが含まれているため、2つ上のレベルに移動する必要があります。つまり、Defines.mqhファイルはプロジェクトのディレクトリ構造のルートにあります。何らかの理由でプロジェクトのルートが変更されても、コンパイラには影響せず、コンパイラは常に同じ場所にあるDefines.mqhファイルを探します。

このような整理整頓はとても面白いものです。特に、ヘッダーベースを整理し始めると、物事を見つけやすく、計画しやすくなります。これによって、特定のファイルが見つからないことを心配することなく、コードやその一部を簡単に配布できるようになります。すべてがきちんと整理され、コードを配布する準備ができていることで、とても楽になります。Defines.mqhファイルをシステムにインクルードする方法を説明したので、早速使用してみましょう。定義の数を増やして、すべてを読みやすくすることができます。ここでの目的には現在の定義で十分ですが、コードがより読みやすくなり、発生した問題を解決しやすくなることを本当に理解するには、以下の例をご覧ください。

if (m_Info.Study == eStudyExecute) ExecuteStudy(memPrice);
if (m_Info.Study identical eStudyExecute) ExecuteStudy(memPrice);
if_case m_Info.Study identical eStudyExecute then ExecuteStudy(memPrice);

この3行は同じ意味であり、コンパイラによって同じように解釈され、まったく同じコードが生成されます。しかしこの場合、Defines.mqhファイルはコンパイラに何をすべきかを指示することができません。新たに2つの定義を追加する必要があります。

#define if_case if(
#define then )

この2行をDefines.mqhファイルに追加すれば、コンパイラは例の3行を正しく理解できるようになります。強調表示された行にご注目ください。ここには、自然言語に非常によく似た言語があります。この3行のうち、この行が最も自然言語に近いので、3行の中で最も高水準であると言えます。コードが高水準か低水準か、というのはこういう意味です。コンパイラにとっては何も変わりませんが、人間の目には3行目の方がずっとシンプルに見えます。これは単純なケースですが、すべてのコードが図に示すように記述される、より複雑なケースを見てみましょう。以前の記事で示したコードでも、読みやすくするために同様の変更が加えられていることを忘れないでください。これは今のところです。

前回の記事で止まったところに戻りましょう。C_Mouseクラスに存在する最後の関数を見てみましょう。


DispatchMessage:外部とのコミュニケーション

何らかの方法でMetaTrader 5プラットフォームからイベントを受け取らなければならないすべてのクラスは、そのポートフォリオにこのDispatchMessage関数を持つことになります。Гшытпшебクラスは生成されたイベントを受信して応答できるようになります。最も重要なことは、MetaTrader 5がイベントベースのプログラムであること、つまりリアルタイム型のプログラムであることを理解することです。これを使用して仕事をするのは、控えめに言ってもかなり難しいです。従って、このようなイベントを扱う場合は、どのようなコードも非常に特殊でなければなりません。しかし、DispatchMessage関数を見る前に、C_Terminalクラスに登場する他のコードに慣れておく必要があります。このコードを以下に示します。

const double AdjustPrice(const double arg) const { return NormalizeDouble(round(arg / m_Infos.PointPerTick) * m_Infos.PointPerTick, m_Infos.nDigits); }

このコードはC_Mouseクラスに配置することもできましたが、他の要因もあってC_Terminalクラスに配置することにしました。このコードは単純に、取引サーバーが期待する値と常に等しくなるように価格を調整しようとする因数分解です。指定された価格が正しくないために、サーバーによって注文が拒否されることがよくあります。取引サーバーに注文を送ろうとするとエラーが返ってくるという理由で、EAを作成することを断念する人も多いです。資産クラスによっては、価格調整のための因数分解がより単純なものもあれば、複数の銘柄を含むより複雑なものもあります。しかし実際には、上記の機能はこれらの要素をすべて管理し、使用される資産の種類に関係なく、常に適切な価格を保証します。リプレイ/シミュレーションシステムでEAを作成して使用するためには、デモ口座であろうとリアル口座であろうと、資産に関係なく価格が正しいことが必要だからです。そのため、この機能を利用し、悪用することもできます。そうすれば、システムがどのようなタイプの市場や資産にも適応することがわかります。この能力を使用して、研究してください。

必要に応じて価格を調整する関数を見たので、次はDispatchMessage関数を見てみましょう。その全コードを以下に示します。

virtual void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam)
   {
      int w equal 0;
      static double memPrice equal 0;
                                
      C_Terminal::DispatchMessage(id, lparam, dparam, sparam);
      switch (id)
      {
         case (CHARTEVENT_CUSTOM + ev_HideMouse):
            ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, clrNONE);
            break;
         case (CHARTEVENT_CUSTOM + ev_ShowMouse):
            ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, m_Info.corLineH);
            break;
         case CHARTEVENT_MOUSE_MOVE:
            ChartXYToTimePrice(GetInfoTerminal().ID, m_Info.Data.Position.X equal (int)lparam, m_Info.Data.Position.Y equal (int)dparam, w, m_Info.Data.Position.dt, m_Info.Data.Position.Price);
            ObjectMove(GetInfoTerminal().ID, def_NameObjectLineH, 0, 0, m_Info.Data.Position.Price equal AdjustPrice(m_Info.Data.Position.Price));
            if (m_Info.Study different eStudyNull) ObjectMove(GetInfoTerminal().ID, def_NameObjectLineV, 0, m_Info.Data.Position.dt, 0);
            m_Info.Data.ButtonStatus equal (uint) sparam;
            if (CheckClick(eClickMiddle) and ((color)ObjectGetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR) different clrNONE)) CreateStudy();
            if (CheckClick(eClickLeft) and (m_Info.Study identical eStudyCreate))
            {
               ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false);
               ObjectMove(GetInfoTerminal().ID, def_NameObjectLineT, 0, m_Info.Data.Position.dt, memPrice equal m_Info.Data.Position.Price);
               m_Info.Study equal eStudyExecute;
            }
            if (m_Info.Study identical eStudyExecute) ExecuteStudy(memPrice);
            break;
         case CHARTEVENT_OBJECT_DELETE:
            if (sparam identical def_NameObjectLineH) CreateLineH();
            break;
      }
   }

上のコードで起こっていることの多くは、プログラミングの経験があまりなくても、コードを見るだけで理解できます。プログラミングの知識がなくてもコードを理解できるでしょうか。コードが自然言語に近くなるような言語でプログラミングすれば、コードは理解しやすくなります。そうすれば、プログラミングを理解していない人でも、そこで何がプログラムされているかを理解することができます。実際、そこで起こっていることの多くは非常に理解しやすく、細かい説明は必要ないほどシンプルです。さて、次の行をご覧ください。

int w equal 0;
static double memPrice equal 0;

コードはこのように宣言されていますが、書かれているのと同じように読むべきです。コンパイラはこのコードを次のように解釈します。

int w = 0;
static double memPrice = 0;

ご覧の通り、違いはありません。どちらの場合も、誰でもコードを理解することができました。最初のケースでは「リテラル」フォーマットがあります。でも心配はいりません。まだ始まったばかりです。この例では、コードをより読みやすくするためのオプションがすべて反映されているわけではありません。

別のコードを見てみましょう。この部分はコードの読みやすさとは直接関係ありませんが、それでも明確にしておく必要があります。

case (CHARTEVENT_CUSTOM + ev_HideMouse):
   ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, clrNONE);
   break;

チャート上の価格線を非表示にしたいときがあります。「ゼロからEAを開発する方法」の連載で示された発注システムに従った人は、いくつかのポイントで価格線が非表示になっていることを見ました。このコードでは、行を非表示にする特定のメソッドを呼び出すことでこれを実現しています。しかし今のところ、C_Mouseクラスに送られるメッセージを使用して、価格線を非表示にすることにしましょう。メソッドの代わりにメッセージを使用することにしたのは、とりわけ、よりモジュール化された、移植しやすいシステムを構築したいからです。そこで、同じ条件を満たす別のメッセージを用意しました。以下をご覧ください。

case (CHARTEVENT_CUSTOM + ev_ShowMouse):
   ObjectSetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR, m_Info.corLineH);
   break;

これらのメッセージの使い方については、まだ心配する必要はありません。将来的に検討します。実際、どちらのメッセージもメソッドや関数であると考えた方が理解しやすなります。しかし、この目的のためにpublicメソッドや関数を追加するのではなく、すべてをメッセージ処理関数という1つの中心点に集中させます。特別な場合のみ、別の方法を用います。

これらのイベントは、特別な呼び出しの結果として発生します。これがどのようにおこなわれるのか知らない方も多いと思うので、後で詳しく説明します。これらは、MetaTrader 5プラットフォームによって発生するイベントではなく、何らかのアクションを実行するために非常に特定の時間にコードによって発生するイベントですが、MetaTrader 5プラットフォームからのイベントも扱う必要があります。これは次のようにおこなわれます。

C_Terminal::DispatchMessage(id, lparam, dparam, sparam);

C_MouseクラスのDispatchMessage関数のこのコード行は、C_Terminalクラスへの呼び出しを転送するため、コードの他の部分でこれをおこなう必要はありません。これにより、プログラミングの見落としを防ぎ、コードを標準化し、プログラミング、分析、作成、修正を迅速におこなうことができます。ただし、すべてのイベントがC_Terminalクラスで処理されるわけではありません。それらの一部はローカル、つまり作業しているクラス内で解決されます。そのようなイベントの例を以下に示します。

case CHARTEVENT_OBJECT_DELETE:
   if (sparam identical def_NameObjectLineH) CreateLineH();
   break;

これは読者向けのイベントのコードです。コンパイラによって次のように解釈されることはご理解いただけると思います。

case CHARTEVENT_OBJECT_DELETE:
   if (sparam == def_NameObjectLineH) CreateLineH();
   break;

コードがどのように提示されるかに関係なく、結果は次のようになります。オブジェクトが銘柄チャートから取り除かれると、プラットフォームはメッセージ(イベント)をトリガーします。このタイプのメッセージを要求したプログラムに、オブジェクトがチャートから削除されたことを通知します。CHART_EVENT_OBJECT_DELETEハンドラを満たした場合、プログラムはそこにあるコードを実行しなければなりません。param定数で指定されたオブジェクトの名前がテストされているものと一致する場合、実行されたコードは価格行を再作成します。

CHART_EVENT_MOUSE_MOVEイベントが少し拡張されました。より大規模であるにもかかわらず、それほど複雑ではありません。プログラミングの知識がなくても、文字通りすべての行を読もうとするだけで、以下のコードの大半を理解することができます。お試しになって、私たちがやっていることを理解しやすくなったか難しくなったかお知らせください。すべてのコードを理解できなくても、余分な努力をせずに可能な限り理解しようとすれば問題ありません。

case CHARTEVENT_MOUSE_MOVE:
   ChartXYToTimePrice(GetInfoTerminal().ID, m_Info.Data.Position.X equal (int)lparam, m_Info.Data.Position.Y equal (int)dparam, w, m_Info.Data.Position.dt, m_Info.Data.Position.Price);
   ObjectMove(GetInfoTerminal().ID, def_NameObjectLineH, 0, 0, m_Info.Data.Position.Price equal AdjustPrice(m_Info.Data.Position.Price));
   if (m_Info.Study different eStudyNull) ObjectMove(GetInfoTerminal().ID, def_NameObjectLineV, 0, m_Info.Data.Position.dt, 0);
   m_Info.Data.ButtonStatus equal (uint) sparam;
   if (CheckClick(eClickMiddle) and ((color)ObjectGetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR) different clrNONE)) CreateStudy();
   if (CheckClick(eClickLeft) and (m_Info.Study identical eStudyCreate))
   {
      ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false);
      ObjectMove(GetInfoTerminal().ID, def_NameObjectLineT, 0, m_Info.Data.Position.dt, memPrice equal m_Info.Data.Position.Price);
      m_Info.Study equal eStudyExecute;
   }
   if (m_Info.Study identical eStudyExecute) ExecuteStudy(memPrice);
   break;

MQL5の関数を呼び出す場面を除けば、コード全体を読むことができ、いくつかの点を理解するのは難しくなかったとおもいます。次は例です。

  • m_Info.StudyeStudyNullと異なる場合、何かを実行する必要があります。
  • m_Info.Data.ButtonStatussparamと等しくなります。
  • 中ボタンが押され、何か(価格線の色)がclrNONEと異なる場合は、次のようにします。
  • マウスの左ボタンが押され、m_Info.StudyeStudyCreateに等しい場合、このアクションが実行されます。
  • eStudyExecuteをm_Info.Studyに設定します。
  • m_Info.StudyeStudyExecuteと等しい場合、これを実行します。

上記で説明したことをすべて読んだとしても、Defines.mqhファイルにさらにいろいろなことを追加することで、私が説明したことよりもさらに読みやすい言語にすることができることがわかるでしょう。単純により多くの要素を追加し、より読みやすいプログラムを作ることができます。これは優れたプログラミング言語の特質であり、技術的に優れたプログラムには必ず存在します。コードをかなり読みやすくするもう1つの方法は、最も重要な関数やポイントには常にコメントを加えることで、この点ではMQL5はC/C++よりかなり優れています。変数やプロシージャにコメントを付けてみましょう。MetaEditorを使用すると、これらのコメントがツールチップとして表示され、非常に便利です。

上記のコードは実際にどのようにプログラムされるのでしょうか。より正確には、コンパイラは上記のコードを実際にどのように見るのでしょうか。これを以下に示します。

case CHARTEVENT_MOUSE_MOVE:
   ChartXYToTimePrice(GetInfoTerminal().ID, m_Info.Data.Position.X = (int)lparam, m_Info.Data.Position.Y = (int)dparam, w, m_Info.Data.Position.dt, m_Info.Data.Position.Price);
   ObjectMove(GetInfoTerminal().ID, def_NameObjectLineH, 0, 0, m_Info.Data.Position.Price = AdjustPrice(m_Info.Data.Position.Price));
   if (m_Info.Study != eStudyNull) ObjectMove(GetInfoTerminal().ID, def_NameObjectLineV, 0, m_Info.Data.Position.dt, 0);
   m_Info.Data.ButtonStatus = (uint) sparam;
   if (CheckClick(eClickMiddle) && ((color)ObjectGetInteger(GetInfoTerminal().ID, def_NameObjectLineH, OBJPROP_COLOR) != clrNONE)) CreateStudy();
   if (CheckClick(eClickLeft) && (m_Info.Study == eStudyCreate))
   {
      ChartSetInteger(GetInfoTerminal().ID, CHART_MOUSE_SCROLL, false);
      ObjectMove(GetInfoTerminal().ID, def_NameObjectLineT, 0, m_Info.Data.Position.dt, memPrice = m_Info.Data.Position.Price);
      m_Info.Study = eStudyExecute;
   }
   if (m_Info.Study == eStudyExecute) ExecuteStudy(memPrice);
   break;

どちらのコードも同じです。そこで、MQL5言語に存在する関数を完全に理解していない方のために、ここで私たちがやっていることを説明しましょう。最初にすることは、プラットフォームから報告されたグラフィカルな座標を価格と時間の座標に変換することです。こうすることで、マウスポインタがチャートに対してどの位置にあるかを知ることができます。次に、取引サーバーの期待値に合わせて価格を調整します。同様に、チャート上の好きな場所に価格線を置くことができます。分析をするのであれば、タイムラインを正しく動かす必要があります。マウスボタンの状態を保存し、中央のボタンが押されて探索されたかどうかを確認します。ただし、分析が実行されるのは、チャートに価格線が表示されている場合に限られます。左ボタンを押すとすぐに分析が始まります。したがって、左ボタンを押したままマウスをドラッグしやすいように、プラットフォームにチャートを動かさないように指示する必要があります。ボタンを押したままにしておくと、チャート上に配置したいすべてのオブジェクトを使用して分析がおこなわれます。

そして記事を終える前に、現段階でのEAのコードを簡単に見ておきましょう。全コードは以下の通りです。

#property copyright "Daniel Jose"
#property description "Generic EA for use on Demo account, replay system/simulator and Real account."
#property description "This system has means of sending orders using the mouse and keyboard combination."
#property description "For more information see the article about the system."
#property version   "1.28"
#property link "https://www.mql5.com/ja/articles/11349"
//+------------------------------------------------------------------+
#include <Market Replay\System EA\Auxiliar\C_Mouse.mqh>
//+------------------------------------------------------------------+
input group "Mouse";
input color     user00 equal clrBlack;          //Price Line
input color     user01 equal clrDarkGreen;      //Positive Study
input color     user02 equal clrMaroon;         //Negative Study
//+------------------------------------------------------------------+
C_Mouse *mouse;
//+------------------------------------------------------------------+
int OnInit()
{
   mouse equal new C_Mouse(user00, user01, user02);
                
   return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   delete mouse;
}
//+------------------------------------------------------------------+
void OnTick() {}
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   (*mouse).DispatchMessage(id, lparam, dparam, sparam);
   ChartRedraw();
}
//+------------------------------------------------------------------+

コードは非常にシンプルです。従って、この段階では、そのプロセスを詳しく説明する必要は特にないので省略します。


結論

これからは、システムに含まれているEAを使用して、システムの動作を監視することができます。しかし、このEAはマウスでしか操作できません。しかし現在では、リプレイ/シミュレーションシステムだけでなく、デモ口座やリアル口座でも使用することができます。このEAは、そのような状況ではまだあまり役に立ちませんが、どのような市場、銘柄、どのような状況でも使用できるため、非常に興味深いものです。

もう1つ重要なことがあります。添付ファイルに、Defines.mqhファイルの内容を使用する最後の2つのクラス(C_TerminalとC_Mouse)があります。これにより、コードがより読みやすくなります。しかし、これは記事の冒頭で述べた、すべてのコードがこの書式に従うことを暗に示したものとは異なります。実際、望まれるなら、このテクニックを使用することができます。C/C++プログラマーとしてキャリアをスタートさせた当初、私はこの方法をしばらく使用して、言語の構文をよりよく理解しました。最初は戸惑うかもしれませんが、時間が経てば慣れます。このテクニックは、特に広範なブーリアンや論理の組み合わせの分析を必要とする複雑なプロジェクトで有用です。この時点で、二重記号の存在は初心者にとって物事を複雑にする可能性があります。例として、次の事実をご覧ください。

経験豊富なプログラマーであっても、論理AND(&)と論理AND(&&)を混同したことがない人はいないでしょう。最初のケースでは、操作はビットごとに実行され、2つ目のケースでは、変数全体が解析され、trueかfalseが返されます。非常に迅速にプログラムを作成する必要があるときに、多くの人がここでつまずきます。

このため、特定のテクニックの知識を過小評価してはなりません。これらは単純に見えるかもしれませんが、実はプログラムをより読みやすくし、その結果、開発のスピードアップに大きく貢献します。私は、ある特定の部分が思うように動作しない理由を解明するために時間を浪費することなく、コードが常に正しいことを保証しながら、タスクをはるかに速く実行できる方法を、かなり興味深い方法で示したと思います。


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

添付されたファイル |
Files_-_BOLSA.zip (1358.24 KB)
Files_-_FOREX.zip (3743.96 KB)
Files_-_FUTUROS.zip (11397.51 KB)
リプレイシステムの開発(第29回):エキスパートアドバイザープロジェクト - C_Mouseクラス(III) リプレイシステムの開発(第29回):エキスパートアドバイザープロジェクト - C_Mouseクラス(III)
C_Mouseクラスを改良した後は、分析のためのまったく新しいフレームワークを作るためのクラスを作ることに集中しましょう。この新しいクラスを作るのに、継承やポリモーフィズムは使用しません。その代わりに、価格線に新しいオブジェクトを追加します。それがこの記事でやろうとしていることです。次回は、分析結果を変更する方法について見るつもりです。これらはすべて、C_Mouseクラスのコードを変更することなくおこなわれます。実際には、継承やポリモーフィズムを使用すれば、もっと簡単に実現できるでしょう。しかし、同じ結果を得る方法は他にもあります。
リプレイシステムの開発(第27回):エキスパートアドバイザープロジェクト-C_Mouseクラス(I) リプレイシステムの開発(第27回):エキスパートアドバイザープロジェクト-C_Mouseクラス(I)
この記事では、C_Mouseクラスを実装します。このクラスは、最高水準でプログラミングする能力を提供します。しかし、高水準や低水準のプログラミング言語について語ることは、コードに卑猥な言葉や専門用語を含めることではありません。逆です。高水準プログラミング、低水準プログラミングというのは、他のプログラマーが理解しやすいか、しにくいかという意味です。
リプレイシステムの開発(第30回):エキスパートアドバイザープロジェクト - C_Mouseクラス(IV) リプレイシステムの開発(第30回):エキスパートアドバイザープロジェクト - C_Mouseクラス(IV)
今日は、プログラマーとしての職業生活のさまざまな段階で非常に役立つテクニックを学びます。多くの場合、制限されているのはプラットフォーム自体ではなく、制限について話す人の知識です。この記事では、常識と創造性があれば、クレイジーなプログラムなどを作成することなく、MetaTrader 5 プラットフォームをより面白くて多用途にし、シンプルでありながら安全で信頼性の高いコードを作成できることを説明します。創造力を駆使して、ソース コードを1行も削除したり追加したりすることなく、既存のコードを変更します。
リプレイシステムの開発(第26回):エキスパートアドバイザープロジェクト-C_Terminalクラス リプレイシステムの開発(第26回):エキスパートアドバイザープロジェクト-C_Terminalクラス
これで、リプレイ/シミュレーションシステムで使用するEAの作成を開始できます。ただし、行き当たりばったりの解決策ではなく、何か改善策が必要です。にもかかわらず、最初の複雑さに怯んではなりません。どこかで始めることが重要で、そうでなければ、その課題を克服しようともせずに、その難しさを反芻してしまうことになります。それこそがプログラミングの醍醐味であり、学習、テスト、徹底的な研究を通じて障害を克服することです。