English Русский Español Deutsch Português
preview
リプレイシステムの開発(第41回):第2段階(II)の開始

リプレイシステムの開発(第41回):第2段階(II)の開始

MetaTrader 5 | 2 8月 2024, 11:01
38 0
Daniel Jose
Daniel Jose

はじめに

前回の「リプレイシステムの開発(第40回):第2段階(I)」では、研究システムとマウスをサポートする指標の作成に着手しました。しかし、その前に質問したいのですが、なぜこの指標を作るのか、想像がつくでしょうか。このようなものを作る方法を示したいという意図の裏には何があるのでしょうか。マウスの指標を作ることで何をしようとしているのでしょうか。

さて、これらの質問にはあまり意味がないかもしれませんが、ご自分のコードを観察するために立ち止まったことがあるでしょうか。異なるコードで同じことを何度も繰り返していることに気づいたことがあるでしょうか。しかし、異なるコードに一貫性や安定性はありません。誤解なさらないでください。プログラミングの経験が何年もある人たちに、何をすべきか、何をすべきでないかを私が指示すべきではありません。また、MQL5言語やその他の専門言語の使い方が間違っているなどと言うつもりはありません。

私はただ、プログラミングの経験が何年もある読者に、同じことの繰り返しをどうにかしてやめさせたいだけです。おそらく、今こそ自分の仕事を注意深く見つめる時なのでしょう。思慮深い計画の欠如のために、同じことを繰り返すのはやめましょう。

実は、リプレイ/シミュレーターのシステムで新しい局面が始まる背景には、隠された理由があります。これについては別の記事ですでに述べました。MQL5での古いやり方にはうんざりしています。私の個人的な規範は一定のルールに則っています。しかし、記事に付けられたコードは異なっていました。私はいつも、できるだけシンプルでわかりやすい文章を心がけていますが、MQL5やMetaTrader 5について何か言っている人をよく見かけます。

私は、他の人たちが達成した以上のことが可能だということを示したいのです。これからは真剣にやりますので、心構えをしてください。私のコードが実際にどのようになるのかも確認します。特定の資産や指標について具体的なことを示すつもりはありませんが、MQL5がMetaTrader 5と同様に、読者が考えているよりもはるかに多くのことができることをお見せします。

前回の記事で、解決すべき未解決の問題が1つあると述べました。この問題を解決することから始めましょう。


C_Mouseクラスの修正

ここで問題になるのは、マウスポインタをどのように操作するかです。前回の記事で紹介したコードが完成しました。指標は、少なくともかなり長い間、変化することはないでしょう。しかし、私たちがデータを使用する必要があるとき、事態をより複雑にする問題があります。

これから説明することを深く理解するためには、MetaTrader 5とMQL5言語について知っていた考えや概念を捨てなければなりません。それらの操作について知っていたことはすべて忘れましょう。まったく違う方法で考えてみましょう。このことが理解できれば、より生産的で安定したコードを生み出すことができるようになるでしょう。

以前の記事で、MetaTrader 5で実行されているプロセスは、指標、EA、スクリプト、またはサービスとしてではなく、関数として見るべきであるという事実をお話しました。関数という考え方は、最適な表現ではないかもしれませんが、一番しっくりくる定義があります。DLLです。そうです。MetaTrader 5で実行されているすべてのプロセス、特に指標はDLLであると考えてるのです。

なぜこんなことを言うのかというと、DLLと同じ概念が、ここで紹介するものにも適用できるからです。今のところ、唯一の指標はマウスです。これでは、何が起こるかを完全かつ包括的に理解することはできません。しかし、どんな偉大な建物も必ず礎石を築くことから始まります。今すぐやりましょう。しかし、いくつかの問題があるため、完全な混乱を招かないよう、作業を完全に単純化しなければなりません。

リプレイシステムの開発(第31回):エキスパートアドバイザープロジェクト - C_Mouseクラス(V)」稿を読んでいただければ: C_Mouseクラスは、C_Studyクラスと同様に、ある方法で動作することにお気づきでしょう。しかし、これらのクラスは、指標を利用するような簡単なプログラミングを可能にするものではありません注意:最大限に活用できないと言っているのではなく、極めて複雑なプログラミングが必要だということです。

このプログラムをシンプルにすることです。そのために、C_Studyクラスからいくつかの要素を取り除き、C_Mouseクラスに移します。しかし、次回の記事で紹介するように、指標をより使いやすくするために、プログラミングや構造化の面でC_Mouseクラスに追加を加えるつもりです。

C_Studyクラスで削除しようとしているのは、以下のコードです。

C_Studyクラスコードの一部

01. #property copyright "Daniel Jose"
02. //+------------------------------------------------------------------+
03. #include "..\C_Mouse.mqh"
04. #include "..\..\Auxiliar\C_Mouse.mqh"
05. #include "..\..\Auxiliar\Interprocess.mqh"
06. //+------------------------------------------------------------------+
07. #define def_ExpansionPrefix "MouseExpansion_"
08. #define def_ExpansionBtn1 def_ExpansionPrefix + "B1"
09. #define def_ExpansionBtn2 def_ExpansionPrefix + "B2"
10. #define def_ExpansionBtn3 def_ExpansionPrefix + "B3"
11. //+------------------------------------------------------------------+
12. #define def_AcessTerminal (*Terminal)
13. #define def_InfoTerminal def_AcessTerminal.GetInfoTerminal()
14. //+------------------------------------------------------------------+
15. class C_Study : public C_Mouse
16. {
17.     protected:
18.     private :
19. //+------------------------------------------------------------------+
20.             enum eStatusMarket {eCloseMarket, eAuction, eInTrading, eInReplay};
21. //+------------------------------------------------------------------+
22.             struct st00
23.             {
24.                     eStatusMarket   Status;
25.                     MqlRates        Rate;
26.                     string          szInfo;
27.                     color           corP,
28.                                     corN;
29.                     int             HeightText;
30.             }m_Info;

ヘッダーファイルC_Study.mqhの場所が変更されました。04行目を03行目に置き換え、InterProcess.mqhヘッダーファイルを参照しなくなったので、05行目も削除しました。

また、20行目を削除し、C_Mouseクラスに含めました。この移動の目的は、後の段階でのプログラミングを容易にするためです。C_Studyクラスに加えられた変更を確認したので、次は、より広範囲にわたる変更が加えられているC_Mouseクラスに移りましょう。

以下に、新しいC_Mouseクラスのコード全体を示します。

C_Mouse.mqhファイルのコード

001. //+------------------------------------------------------------------+
002. #property copyright "Daniel Jose"
003. //+------------------------------------------------------------------+
004. #include "C_Terminal.mqh"
005. #include "Interprocess.mqh"
006. //+------------------------------------------------------------------+
007. #define def_MousePrefixName "MouseBase_"
008. #define def_NameObjectLineH def_MousePrefixName + "H"
009. #define def_NameObjectLineV def_MousePrefixName + "TV"
010. #define def_NameObjectLineT def_MousePrefixName + "TT"
011. #define def_NameObjectStudy def_MousePrefixName + "TB"
012. //+------------------------------------------------------------------+
013. #define def_AcessTerminal (*Terminal)
014. #define def_InfoTerminal def_AcessTerminal.GetInfoTerminal()
015. //+------------------------------------------------------------------+
016. class C_Mouse
017. {
018.    public  :
019.            enum eStatusMarket {eCloseMarket, eAuction, eInTrading, eInReplay};
020.            enum eBtnMouse {eKeyNull = 0x00, eClickLeft = 0x01, eClickRight = 0x02, eSHIFT_Press = 0x04, eCTRL_Press = 0x08, eClickMiddle = 0x10};
021.            struct st_Mouse
022.            {
023.                    struct st00
024.                    {
025.                            int       X,
026.                                      Y;
027.                            double    Price;
028.                            datetime  dt;
029.                    }Position;
030.                    uint    ButtonStatus;
031.                    bool    ExecStudy;
032.            };
033. //+------------------------------------------------------------------+
034.    protected:
035.            enum eEventsMouse {ev_HideMouse, ev_ShowMouse};
036. //+------------------------------------------------------------------+
037.            void CreateObjectInfo(int x, int w, string szName, color backColor = clrNONE) const
038.                    {
039.                            if (m_Mem.IsTranslator) return;
040.                            def_AcessTerminal.CreateObjectGraphics(szName, OBJ_BUTTON, clrNONE);
041.                            ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_STATE, true);
042.                    	ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_BORDER_COLOR, clrBlack);
043.                            ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_COLOR, clrBlack);
044.                            ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_BGCOLOR, backColor);
045.                            ObjectSetString(def_InfoTerminal.ID, szName, OBJPROP_FONT, "Lucida Console");
046.                            ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_FONTSIZE, 10);
047.                            ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_CORNER, CORNER_LEFT_UPPER); 
048.                            ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_XDISTANCE, x);
049.                            ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_YDISTANCE, TerminalInfoInteger(TERMINAL_SCREEN_HEIGHT) + 1);
050.                            ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_XSIZE, w); 
051.                            ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_YSIZE, 18);
052.                    }
053. //+------------------------------------------------------------------+
054.    private :
055.            enum eStudy {eStudyNull, eStudyCreate, eStudyExecute};
056.            struct st01
057.            {
058.                    st_Mouse Data;
059.                    color    corLineH,
060.                             corTrendP,
061.                             corTrendN;
062.                    eStudy   Study;
063.            }m_Info;
064.            struct st_Mem
065.            {
066.                    bool     CrossHair,
067.                             IsFull,
068.                             IsTranslator;
069.                    datetime dt;
070.                    string   szShortName;
071.            }m_Mem;
072. //+------------------------------------------------------------------+
073.            C_Terminal *Terminal;
074. //+------------------------------------------------------------------+
075.            void GetDimensionText(const string szArg, int &w, int &h)
076.                    {
077.                            TextSetFont("Lucida Console", -100, FW_NORMAL);
078.                            TextGetSize(szArg, w, h);
079.                            h += 5;
080.                            w += 5;
081.                    }
082. //+------------------------------------------------------------------+
083.            void CreateStudy(void)
084.                    {
085.                            if (m_Mem.IsFull)
086.                            {
087.                                    def_AcessTerminal.CreateObjectGraphics(def_NameObjectLineV, OBJ_VLINE, m_Info.corLineH);
088.                                    def_AcessTerminal.CreateObjectGraphics(def_NameObjectLineT, OBJ_TREND, m_Info.corLineH);
089.                                    ObjectSetInteger(def_InfoTerminal.ID, def_NameObjectLineT, OBJPROP_WIDTH, 2);
090.                                    CreateObjectInfo(0, 0, def_NameObjectStudy);
091.                            }
092.                            m_Info.Study = eStudyCreate;
093.                    }
094. //+------------------------------------------------------------------+
095.            void ExecuteStudy(const double memPrice)
096.                    {
097.                            double v1 = GetInfoMouse().Position.Price - memPrice;
098.                            int w, h;
099.                            
100.                            if (!CheckClick(eClickLeft))
101.                            {
102.                                    m_Info.Study = eStudyNull;
103.                                    ChartSetInteger(def_InfoTerminal.ID, CHART_MOUSE_SCROLL, true);
104.                                    if (m_Mem.IsFull)       ObjectsDeleteAll(def_InfoTerminal.ID, def_MousePrefixName + "T");
105.                            }else if (m_Mem.IsFull)
106.                            {
107.                                    string sz1 = StringFormat(" %." + (string)def_InfoTerminal.nDigits + "f [ %d ] %02.02f%% ",
108.                                            MathAbs(v1), Bars(def_InfoTerminal.szSymbol, PERIOD_CURRENT, m_Mem.dt, GetInfoMouse().Position.dt) - 1, MathAbs((v1 / memPrice) * 100.0)));
109.                                    GetDimensionText(sz1, w, h);
110.                                    ObjectSetString(def_InfoTerminal.ID, def_NameObjectStudy, OBJPROP_TEXT, sz1);                                                                                                                           
111.                                    ObjectSetInteger(def_InfoTerminal.ID, def_NameObjectStudy, OBJPROP_BGCOLOR, (v1 < 0 ? m_Info.corTrendN : m_Info.corTrendP));
112.                                    ObjectSetInteger(def_InfoTerminal.ID, def_NameObjectStudy, OBJPROP_XSIZE, w);
113.                                    ObjectSetInteger(def_InfoTerminal.ID, def_NameObjectStudy, OBJPROP_YSIZE, h);
114.                                    ObjectSetInteger(def_InfoTerminal.ID, def_NameObjectStudy, OBJPROP_XDISTANCE, GetInfoMouse().Position.X - w);
115.                                    ObjectSetInteger(def_InfoTerminal.ID, def_NameObjectStudy, OBJPROP_YDISTANCE, GetInfoMouse().Position.Y - (v1 < 0 ? 1 : h));                            
116.                                    ObjectMove(def_InfoTerminal.ID, def_NameObjectLineT, 1, GetInfoMouse().Position.dt, GetInfoMouse().Position.Price);
117.                                    ObjectSetInteger(def_InfoTerminal.ID, def_NameObjectLineT, OBJPROP_COLOR, (memPrice > GetInfoMouse().Position.Price ? m_Info.corTrendN : m_Info.corTrendP));
118.                            }
119.                            m_Info.Data.ButtonStatus = eKeyNull;
120.                    }
121. //+------------------------------------------------------------------+
122.    public  :
123. //+------------------------------------------------------------------+
124.            C_Mouse(const string szShortName)
125.                    {
126.                            Terminal = NULL;
127.                            m_Mem.IsTranslator = true;
128.                            m_Mem.szShortName = szShortName;
129.                    }
130. //+------------------------------------------------------------------+
131.            C_Mouse(C_Terminal *arg, color corH = clrNONE, color corP = clrNONE, color corN = clrNONE)
132.                    {
133.                            m_Mem.IsTranslator = false;
134.                            Terminal = arg;
135.                            if (CheckPointer(Terminal) == POINTER_INVALID) SetUserError(C_Terminal::ERR_PointerInvalid);
136.                            if (_LastError != ERR_SUCCESS) return;
137.                            m_Mem.CrossHair = (bool)ChartGetInteger(def_InfoTerminal.ID, CHART_CROSSHAIR_TOOL);
138.                            ChartSetInteger(def_InfoTerminal.ID, CHART_EVENT_MOUSE_MOVE, true);
139.                            ChartSetInteger(def_InfoTerminal.ID, CHART_CROSSHAIR_TOOL, false);
140.                            ZeroMemory(m_Info);
141.                            m_Info.corLineH  = corH;
142.                            m_Info.corTrendP = corP;
143.                            m_Info.corTrendN = corN;
144.                            m_Info.Study = eStudyNull;
145.                            if (m_Mem.IsFull = (corP != clrNONE) && (corH != clrNONE) && (corN != clrNONE))
146.                                    def_AcessTerminal.CreateObjectGraphics(def_NameObjectLineH, OBJ_HLINE, m_Info.corLineH);
147.                    }
148. //+------------------------------------------------------------------+
149.            ~C_Mouse()
150.                    {
151.                            if (CheckPointer(Terminal) == POINTER_INVALID) return;
152.                            ChartSetInteger(def_InfoTerminal.ID, CHART_EVENT_OBJECT_DELETE, 0, false);
153.                            ChartSetInteger(def_InfoTerminal.ID, CHART_EVENT_MOUSE_MOVE, false);
154.                            ChartSetInteger(def_InfoTerminal.ID, CHART_CROSSHAIR_TOOL, m_Mem.CrossHair);
155.                            ObjectsDeleteAll(def_InfoTerminal.ID, def_MousePrefixName);
156.                    }
157. //+------------------------------------------------------------------+
158. inline bool CheckClick(const eBtnMouse value) 
159.                    {
160.                            return (GetInfoMouse().ButtonStatus & value) == value;
161.                    }
162. //+------------------------------------------------------------------+
163. inline const st_Mouse GetInfoMouse(void)
164.                    {
165.                            if (m_Mem.IsTranslator)
166.                            {
167.                                    double Buff[];
168.                                    uCast_Double loc;
169.                                    int handle = ChartIndicatorGet(ChartID(), 0, m_Mem.szShortName);
170.                                    
171.                                    ZeroMemory(m_Info.Data);
172.                                    if (CopyBuffer(handle, 0, 0, 4, Buff) == 4)
173.                                    {
174.                                            m_Info.Data.Position.Price = Buff[0];
175.                                            loc.dValue = Buff[1];
176.                                            m_Info.Data.Position.dt = loc._datetime;
177.                                            loc.dValue = Buff[2];
178.                                            m_Info.Data.Position.X = loc._int[0];
179.                                            m_Info.Data.Position.Y = loc._int[1];
180.                                            loc.dValue = Buff[3];
181.                                            m_Info.Data.ButtonStatus = loc._char[0];
182.                                            IndicatorRelease(handle);
183.                                    }
184.                            }
185. 
186.                            return m_Info.Data;
187.                    }
188. //+------------------------------------------------------------------+
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.IsTranslator) switch (id)
195.                            {
196.                                    case (CHARTEVENT_CUSTOM + ev_HideMouse):
197.                                            if (m_Mem.IsFull)       ObjectSetInteger(def_InfoTerminal.ID, def_NameObjectLineH, OBJPROP_COLOR, clrNONE);
198.                                            break;
199.                                    case (CHARTEVENT_CUSTOM + ev_ShowMouse):
200.                                            if (m_Mem.IsFull) ObjectSetInteger(def_InfoTerminal.ID, def_NameObjectLineH, OBJPROP_COLOR, m_Info.corLineH);
201.                                            break;
202.                                    case CHARTEVENT_MOUSE_MOVE:
203.                                            ChartXYToTimePrice(def_InfoTerminal.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);
204.                                            if (m_Mem.IsFull) ObjectMove(def_InfoTerminal.ID, def_NameObjectLineH, 0, 0, m_Info.Data.Position.Price = def_AcessTerminal.AdjustPrice(m_Info.Data.Position.Price));
205.                                            m_Info.Data.Position.dt = def_AcessTerminal.AdjustTime(m_Info.Data.Position.dt);
206.                                            ChartTimePriceToXY(def_InfoTerminal.ID, w, m_Info.Data.Position.dt, m_Info.Data.Position.Price, m_Info.Data.Position.X, m_Info.Data.Position.Y);
207.                                            if ((m_Info.Study != eStudyNull) && (m_Mem.IsFull)) ObjectMove(def_InfoTerminal.ID, def_NameObjectLineV, 0, m_Info.Data.Position.dt, 0);
208.                                            m_Info.Data.ButtonStatus = (uint) sparam;
209.                                            if (CheckClick(eClickMiddle))
210.                                                    if ((!m_Mem.IsFull) || ((color)ObjectGetInteger(def_InfoTerminal.ID, def_NameObjectLineH, OBJPROP_COLOR) != clrNONE)) CreateStudy();
211.                                            if (CheckClick(eClickLeft) && (m_Info.Study == eStudyCreate))
212.                                            {
213.                                                    ChartSetInteger(def_InfoTerminal.ID, CHART_MOUSE_SCROLL, false);
214.                                                    if (m_Mem.IsFull)       ObjectMove(def_InfoTerminal.ID, def_NameObjectLineT, 0, m_Mem.dt = GetInfoMouse().Position.dt, memPrice = GetInfoMouse().Position.Price);
215.                                                    m_Info.Study = eStudyExecute;
216.                                            }
217.                                            if (m_Info.Study == eStudyExecute) ExecuteStudy(memPrice);
218.                                            m_Info.Data.ExecStudy = m_Info.Study == eStudyExecute;
219.                                            break;
220.                                    case CHARTEVENT_OBJECT_DELETE:
221.                                            if ((m_Mem.IsFull) && (sparam == def_NameObjectLineH)) def_AcessTerminal.CreateObjectGraphics(def_NameObjectLineH, OBJ_HLINE, m_Info.corLineH);
222.                                            break;
223.                            }
224.                    }
225. //+------------------------------------------------------------------+
226. };
227. //+------------------------------------------------------------------+
228. #undef def_AcessTerminal
229. #undef def_InfoTerminal
230. //+------------------------------------------------------------------+
231. #undef def_MousePrefixName
232. #undef def_NameObjectLineV
233. #undef def_NameObjectLineH
234. #undef def_NameObjectLineT
235. #undef def_NameObjectStudy
236. //+------------------------------------------------------------------+
237. 

ここでフルコードを提供する理由は、(少なくとも今のところは)アプリケーション内にファイルが存在しないからです。そのため、この改善を利用したい人は、指定されたコードを使用することで利用できます。システムがより高度な段階になれば、再び投資を回収しますが、現時点では利用できません。 

コードを見ると、ハイライトされている箇所があるのがわかるでしょう。この2つには一定の意味がありますが、詳しくは触れません。なぜなら、そのほとんどが自明のことだからです。

C_Studyクラスの20行目から削除されたコードは、C_Mouseクラスの19行目にあります。さて、C_Mouse.mqhファイルの18行目を見てみましょう。ここで、publicの部分を宣言します。しかし、なぜそれが必要なのでしょうか。それがなければ、どんな情報にも必要なレベルのアクセスができないからです。このデータを公開する必要があります。通常、この部分は一度しか使用しませんが、protectedデータを最初に、privateデータを次に、そしてpublicデータを最後に実行するという私の習慣のせいで、122行目にも同じ部分があります。しかし、これは私が慣れ親しんだプログラミングスタイルによるものです。

20行目には、すでにC_Mouseクラスに存在していたがpublicではなかった別の列挙と、21行目から32行目までの構造体があります。この場合、構造体はpublicグローバル変数では使用されません。クラス内でpublicグローバル変数を宣言するのは良い習慣ではありません。グローバルクラス変数は常にprivateかprotectedでなければならず、publicであってはなりません。

34行目から、データはもはや公開されていません。ここには保護された部分があり、データ、機能、手続きの保護が保証されています。これは以前の記事ですでに見たことですが、問題はそこではありません。問題は39行目の確認にあります。この確認は以前には存在しませんでした。確認対象の変数が値「true」を持つ場合、CreateObjectInfoメソッドで作成されるオブジェクトを作成することはできません。なぜそうするのでしょうか。これを理解するためには、コードを詳しく見る必要があります。

次に、2つの変数が宣言されている2行があります。68行目と70行目です。当初は公表されたコードにはありませんでした。しかし、この場合、これらの変数は必要です。その理由の1つが39行目に示されている、メソッドや関数の実行を許可したり禁止したりすることです。165行目と194行目も同様です。165行目の場合は、もっと強い動機があります。これについては後ほど説明します。しかし、194行目の理由は39行目と同じで、関数やメソッドの実行を避けるためです。翻訳モードでは関数やメソッドが正しく機能しないか実行されないからです。

予想されるように、これらの変数はクラスのコンストラクタで初期化されます。しかし、その間にクラスのコンストラクタはなくなってしまいます。これでC_Mouseクラスのコンストラクタが2つできました😱😵😲。OOPプログラミングに慣れていない方にとって、これは恐らく恐怖でしょうが、これはOOPとしてはまったく普通のことです。コンストラクタの1つは、124行目と129行目の間に書かれています。もう1つのコンストラクタは131行目と147行目の間にあります。コンストラクタは2つありますが、デストラクタは1つしかありません。

コンストラクタの1つはある目的のために使われ、もう1つは別の目的のために使われます。このためにprivateグローバル変数が使われます。それがなければ、このような分離はできません。

では、コンストラクタが2つある理由を見てみましょう。第一に、必要な需要を満たすためだけに2番目のクラスを作る意味はありません。第二に、既存のコードを再利用できるように実行の流れをコントロールできます。これらはすべて、継承を作成したり、データ、関数、プロシージャを操作したりすることなく実行できます。

よく見ると、これまで私たちがやってきたことは、2つのコードを分離することでした。1つはpublic、あと1つはprotectedです。つまり、ある目的を果たすためにC_Mouseクラスを使用するのであれば、使用モデルを持つことになります。しかし、他の種類の目的を果たすとなると、別のモデルを持つことになります。ただし、クラスを使ってプログラミングする方法は、関数の中でクラスを使っても、いつも同じです。

131行目と147行目の間に書かれているコンストラクタを見てください。リプレイシステムの開発(第31回)EAプロジェクト - C_Mouseクラス(V)」で紹介したものと実質的に変わらないことにお気づきでしょう。このようにしたのは、このコンストラクタが、クラス内に存在するオブジェクトをコードで使用する際に、クラスの目的を果たす責任を負うからです。このコンストラクタとオリジナルのコンストラクタの違いは133行目で、新しい変数を初期化して、クラスをオリジナルの形で使用することを示しています。

このようなことが起こるということは、コードのほとんどは変わらないということであり、この特別な記事で提供される説明は、依然として関連性があるということです。次に、このクラスの2つ目の使い方に注目しましょう。これをおこなうには、まず124行目から129行目にかけてのコンストラクタのコードを見ます。シンプルではありますが、実際に必要とされるすべての変数を初期化していることに注意すべきです。

これにより、このクラスを翻訳機として使いやすくなります。たぶん、どうすればいいのか、なぜそうするのか理解できなかったのでしょう。しかし、ここではマウスポインタ翻訳機としてC_Mouseクラスを使用することにします。これはかなり複雑で難しいことのように思えるのでしょうか。でも、全然難しくありません。これには理由があります。

このことを理解するには、少し考える必要があります。指標、EA、スクリプト、その他何でもそうですが、プログラムを作成するとき、私たちは頻繁に繰り返されることを追加する傾向があります。その1つがマウスの扱い方です。もしすべてのEAで、研究やマウス分析を生成するための関数を追加しなければならないとしたら、コードは決して真の信頼性を持つことはないでしょう。しかし、長く使えるものを作る場合は、他のコードとは無関係に改良することができます。そうなれば、新しい種類のプログラムができます。当然、コードの信頼性と効率は格段に向上します。

このクラスでは、常にチャート上にマウスポインタがあることを前提とします。覚えておいてください。何事も想定してはいけませんが、ここでは指標がチャート上に表示されることを想定します。C_Mouseクラスを翻訳機として使用する人は、この事実を知っておかなければなりません。このクラスは、指標がチャート上にあると仮定します

この事実に問題がなければ、次の質問に進むことができます。実際、C_Mouseクラスが指標を翻訳してくれる必要はありません。これは、作成されたプログラム内で直接実行できるためです。しかし、この翻訳をクラスに任せる方がずっと簡単で便利です。というのも、翻訳機を使いたくなければ、クラスのコンストラクタを変更して、プログラムにイベント処理の呼び出しを追加すればよいからです。

そうすれば、自分の仕事に対処するのがどれほど楽になるかがわかるでしょう。それでも、翻訳機システムは使ってください。翻訳機システムの仕組みを理解するには、163行目のGetInfoMouse関数を見てください。最初はconstant関数でしたが、今は違います。データは関数の外部では変更できませんが、内部では変更する必要があります。

前回の「リプレイシステムの開発(第40回)第2段階の開始(I)」稿で述べたことに戻りましょう。指標バッファのデータを解釈する、いや、解釈するためのコーディングスタンダードを維持するのは非常に難しいことがおわかりいただけるでしょう。そこで、この標準化を実現するためにC_Mouseクラスを修正する方法を紹介しましょう。これがどれほど難しいかを想像するために、マウスポインタを使用する必要があるたびに、関数CheckClickGetInfoMouseで見たのと同じことを書かなければならないと考えてみましょう。これはかなり面倒です。

では、その様子をご覧ください。CheckClick関数から始めましょう。この関数では、ポインタとして、あるいは翻訳機として、マウスデータに値を読み込んで確認するだけです。指標を分析するためであれ、指標そのものを使用するためであれ、どのような場合であれ、これをおこないます。160行目では、分析対象のボタンが作動したかどうか、つまり押されたかどうかを確認します。

これが理解すべき問題です。C_Mouseクラスを翻訳機として使おうが、ポインタとして使おうが、CheckClick関数とGetInfoMouse関数からは常に何らかのレスポンスが返ってきます。常にです。この答えは、どこで情報を使おうとも、常にマウスが何をしているかを表しています。

CheckClickが出した答えを理解するためには、GetInfoMouse関数がどのように動作するのかを追って理解する必要があります。この関数は163行目以降から見ることができます。

関数の165行目では、クラスを翻訳機として使っているのか、ポインタとして使っているのかを確認しています。確認が通れば、クラスは翻訳機モードになり、ポインタバッファにアクセスする必要があります。この質問は複雑でもあり、単純でもあります。まずは簡単なところから見てみましょう。

171行目では、戻り値構造のデータをリセットしています。これは実際には、58行目で宣言されているprivateグローバルクラス変数です。この後、MetaTrader 5に指標バッファの読み込みを依頼します。172行目からの読み込みが正しければ、データを戻り値構造体に変換し始めます。

データ変換はデータ書き込みと同じロジックに従います。関連するコードは、前回の記事のSetBuffer関数で見ることができます。物事を簡単にするために、以下に同じ関数を提供します。

指標コードの断片

102. inline void SetBuffer(void)
103. {
104.    uCast_Double Info;
105.    
106.    m_posBuff = (m_posBuff < 0 ? 0 : m_posBuff);
107.    m_Buff[m_posBuff + 0] = (*Study).GetInfoMouse().Position.Price;
108.    Info._datetime = (*Study).GetInfoMouse().Position.dt;
109.    m_Buff[m_posBuff + 1] = Info.dValue;
110.    Info._int[0] = (*Study).GetInfoMouse().Position.X;
111.    Info._int[1] = (*Study).GetInfoMouse().Position.Y;
112.    m_Buff[m_posBuff + 2] = Info.dValue;
113.    Info._char[0] = ((*Study).GetInfoMouse().ExecStudy == C_Mouse::eStudyNull ? (char)(*Study).GetInfoMouse().ButtonStatus : 0);
114.    m_Buff[m_posBuff + 3] = Info.dValue;
115. }

指標フラグメントの107行目の情報が、クラスの174行目でデコードされることに注意してください。ほとんどの場合、翻訳は非常に簡単ですが、コーディング中に作られたルールを守らなければなりません。これは、指標フラグメントの112行目のデータを保存すればよくわかります。この場合、2つの値をdoubleに圧縮していることに注意してください。翻訳に関しては、その逆をやらなければなりません。これは、クラスの177行目で値をキャプチャし、178行目と179行目で、後で使用するために値を適切な場所に配置しています。

指標フラグメントの113行目でも同じことが起こり、マウスクリックの値を保存しています。そして、それをクラスの181行目で翻訳します。しかし、ここでもう一度、指標フラグメントの113行目を見てみましょう。学習モードの場合、三項演算子は値ゼロを保持することに注意してください。このことを理解しておくことが重要です。もし、指標を使った学習をしていて、その翻訳にクラスが使われているのであれば、CheckClick関数でクリックを確認すると、falseを返します。もちろん、指標とクラスを翻訳機として使えば、このようなことは常に起こります。

これは最も単純で理解しやすい部分ですが、前述のように、複雑で難しいという別の部分もあります。

これは、クラスを翻訳機として使用するときに現れます。しかし、私たちは指標バッファにアクセスできません。これは通常、指標がチャートから取り除かれたときに起こります。これが起こると、169行目でヌルハンドラが生成され、読み込むバッファがなくなります。データを復元する171行目を実行しなければなりません。

これは、指標データを使って何かをしようとしたときに、さまざまな違反や失敗につながる可能性があります。システムは常にゼロを報告しますが、実際にはクリックや動きの肯定的な証拠はありません。これについては、まだ問題があります。今回のケースではありませんが、他のケースでも問題になるでしょう。そうなり次第、この問題に戻ります。


C_Mouseクラスを翻訳機として使用する

このトピックについては後ほど詳しく説明するので、以下の部分は主にデモンストレーションのために提供されています。

リプレイシステムの開発(第31回)エキスパートアドバイザープロジェクト - C_Mouseクラス(V)」稿と同じように機能するEAを見てみましょう。 ただし、そのコードは異なる方法で書かれます。

エキスパートアドバイザーのコード

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property description "Generic EA for use on Demo account, replay system/simulator and Real account."
04. #property description "This system has means of sending orders using the mouse and keyboard combination."
05. #property description "For more information see the article about the system."
06. #property version   "1.41"
07. #property icon "/Images/Market Replay/Icons/Replay - EA.ico"
08. #property link "https://www.mql5.com/ja/articles/11607"
09. //+------------------------------------------------------------------+
10. #include <Market Replay\Auxiliar\C_Mouse.mqh>
11. //+------------------------------------------------------------------+
12. C_Mouse *mouse = NULL;
13. //+------------------------------------------------------------------+
14. int OnInit()
15. {
16.     mouse = new C_Mouse("Indicator Mouse Study");
17.     
18.     return INIT_SUCCEEDED;
19. }
20. //+------------------------------------------------------------------+
21. void OnTick() 
22. { }
23. //+------------------------------------------------------------------+
24. void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
25. {
26.     C_Mouse::st_Mouse Infos;
27.     
28.     switch (id)
29.     {
30.             case CHARTEVENT_MOUSE_MOVE:
31.                     Infos = (*mouse).GetInfoMouse();
32.                     Comment((string)Infos.Position.Price + " :: [" + TimeToString(Infos.Position.dt), "]");
33.                     break;
34.     }
35. }
36. //+------------------------------------------------------------------+
37. void OnDeinit(const int reason)
38. {
39.     delete mouse;
40. }
41. //+------------------------------------------------------------------+

見た目にはそう見えませんが、上記のコードは紹介した記事のコードと同じ動作をしますが、よりシンプルで実用的、そして信頼性が高くなります。その理由は今すぐには理解できませんが、コーディングの旅を進めるうちに徐々に理解できるようになるでしょう。

おそらく、私たちが超複雑なことをやっているわけではないことはご理解いただけると思います。ここでは、指示されたものはすべてチャートに記載されると仮定します。16行目で指標の短い名前を示し、39行目でC_Mouseクラスを削除しています。

31行目と32行目を見てください。マウスにチャートデータを知らせてくれます。

これの一番いいところは、16行目でクラスを指標として使用することを宣言すれば、OnChatEvent関数内でDispatchMessage関数の呼び出しを追加するだけで、グラフィカル指標を使用するのと同じ効果が得られることです。つまり、プログラミングは変わりません。その代わり、これは私たちが必要としているものへの適応に過ぎないでしょう。

この関数を翻訳機として使いたい場合、EAはマウスがどこで何をしているのかわかるように分析し、常に適切な報告をします。


結論

物事の仕組みを理解することが重要です。そうでなければ、次の記事で完全に迷子になってしまいます。すべてがもっと複雑な形でおこなわれるようになります。この2つの記事で紹介したことは複雑に見えますが、すべてプログラミングの知識があまりない人向けです。過去2回の記事で取り上げたことはすべて、Chart Traderアプリを追加するためのちょっとした準備に過ぎません。次回の記事では、私たちのシステムにChart Traderを追加し、開発を始めます。このアプリを使えば、市場で直接取引できるようになります。これは非常に便利で重要なことです。特に既存の成行注文システムに頼ることができないからです。そのため、独自のソリューション、つまりChart Traderを開発する必要があります。

にもかかわらず、私たちはまだMQL5の基本レベルで仕事をしています。この教材が難しいと思っても、まだごく基本的なレベルです。でも、難し過ぎると思ったら少し心配してください。これは、MQL5を深く勉強していないからかもしれません。どのような地面を歩いても、高い丘の上にいるような気分になりますが、誰かが、これまでずっと海抜ゼロメートル地帯を歩いていたことを教えてくれるまでではです。信じてください。すぐに、最新の記事で目にしたすべてが、子供なら誰でもできる子供の遊びだと思うようになるでしょう。さあ、準備をしましょう。厳しい状況がやってきます。そんなときが来たら、またこのマウスポインタの問題に戻りましょう。


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

添付されたファイル |
Anexo.zip (420.65 KB)
EAのサンプル EAのサンプル
一般的なMACDを使ったEAを例として、MQL4開発の原則を紹介します。
リプレイシステムの開発(第40回):第2段階の開始(I) リプレイシステムの開発(第40回):第2段階の開始(I)
今日は、リプレイ/シミュレーターシステムの新しい段階について話しましょう。この段階で、会話は本当に面白くなり、内容もかなり濃くなります。記事を熟読し、そこに掲載されているリンクを利用することを強くお勧めします。そうすることで、内容をより深く理解することができます。
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法 エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
この記事では、MT4において複数のEAの衝突をさける方法を扱います。ターミナルの操作、MQL4の基本的な使い方がわかる人にとって、役に立つでしょう。
リプレイシステムの開発(第39回):道を切り開く(III) リプレイシステムの開発(第39回):道を切り開く(III)
開発の第2段階に進む前に、いくつかのアイデアを修正する必要があります。MQL5に必要なことをさせる方法をご存知ですか。ドキュメントに書かれている以上のことをしようとしたことはありますか。そうでないなら、準備をしましょう。ここでは、ほとんどの人が普段やらないことをやるからです。