リプレイシステムの開発(第30回):エキスパートアドバイザープロジェクト - C_Mouseクラス(IV)
はじめに
前回の「リプレイシステムの開発(第29回):エキスパートアドバイザープロジェクト - C_Mouseクラス(III)」稿では、コードの一部を壊さずに研究機能を拡張できるようにC_Mouseクラスを設計しました。コードを並行して作成できるプログラミング手法を利用しているため、組織的な方法で開発するメインプロジェクトが1つあります。同時に、必要に応じて、追加の機能をシステムに追加できます。こうすることで、これらの関数を実装するときに、メインコードはまったく変更されず、継承の過度の使用によってフリーズすることもありません。
オブジェクト指向プログラミング(OOP)は優れたプログラミング方法ですが、何が起こるかを厳密に制御し、システムの成長に伴う奇妙なバグを回避したい実稼働プロジェクトに非常に適しています。プロジェクトの一部を並行して開発する必要がある場合があります。奇妙に聞こえるかもしれませんが、プログラムに何らかの関数やメソッドを追加するとき、その初期段階(テスト段階)の関数を、既に進んだ段階である開発段階にあるコードの途中に配置するのはあまり適切ではありません。つまり、検証済みで動作しているコードにテストされていない関数を追加するべきではありません。これは、予期しない障害につながる可能性があります。
このような欠陥のために、プロジェクト全体を開発の初期段階に戻さなければならないことがよくあります。場合によっては、新しい関数がコードに埋め込まれているため、プロジェクトを以前の段階に戻すよりも削除する方がはるかに困難になることがあります。多くの人、特に初心者のプログラマーは、開発の初期段階に戻るためのディレクトリ構造を実際には使用しませんが、そのようなディレクトリ構造を使用しなくても、システムを追加されたリソースが実際には完了したプロジェクトの一部になっていない時点に戻すことができる特定のテクニックを使用することができます。
このようにして、最終プロジェクトは問題なく進行しながら、並行して開発を進めることができます。その一環として、前回の記事ではポインタの使用方法について説明しました。ここでさらに一歩進めて、基本モデルに基づいてより複雑な研究をしてみましょう。研究またはリソースが最終プロジェクトに適していることが判明し、より高度なテスト段階に合格し、十分に安定性と信頼性があることが確認できたならば、メインクラスシステムに含めることができます。したがって、以前はマイナープロジェクトと考えられていたものが最終プロジェクトの一部となり、クラス システムに継承され、継承されます。
これを実証するために、C_Mouseクラスの変更を作成しますが、継承とポリモーフィズムは使用しません。C_Mouseクラスに存在する元のシステムとは異なる、完全に異なる分析モデルが得られます。これをおこなうには、前の記事で説明した、C_Studiesクラスを継承する(または継承しない)新しいクラスを作成します。C_Studysクラスを継承するかどうかは、実際的な問題というよりも個人的な問題です。実際、どちらのプロジェクトであっても、一方のプロジェクトは並行して作業できるため、他方のプロジェクトとは何の関係もありません。それにもかかわらず、メイン システムに属するコードはすべて、このクラスを拡張するコードが安定していて、最終プロジェクトで使用するのに十分興味深いとみなされるまで、C_Mouseクラスを継承します。
プログラミングに進む前に、システムは2つの異なる方法で進行できることを理解しておくことが重要です。選択する道は、何をしたいのか、どこまで行きたいのかによって異なります。2つの方向があり、それらの差は非常に小さいため、両方を見てみましょう。添付のコードでは、2つの方向のいずれかにアクセスできます。ただし、必要に応じて、必要な変更を加えて別の方向を選択することもできます。
ここでの私の考えはプラットフォーム内で何ができるかを示すことであり、それをどのようにおこなうべきかではありません。
C_Terminalクラスへの追加
デモンストレーション目的でプログラミングしているこのシステムでは、メインコードへの追加は必要ありませんが、実際的な理由から、コードの開発中に頻繁に使用するオブジェクトの作成のテストを開始するために、銘柄チャート上にオブジェクトを作成する一般的なコードをいくつか追加します。こうすることで、最初からテストと改善を開始できます。このコードはずっと前に開発されており、より適切な場所を選択することをすでに検討しています。より適切な場所が見つかるまで、作成関数は以下に示すようにC_terminalクラス内にあります。
inline void CreateObjectGraphics(const string szName, const ENUM_OBJECT obj, const color cor, const int zOrder = -1) { ObjectCreate(m_Infos.ID, szName, obj, 0, 0, 0); ObjectSetString(m_Infos.ID, szName, OBJPROP_TOOLTIP, "\n"); ObjectSetInteger(m_Infos.ID, szName, OBJPROP_BACK, false); ObjectSetInteger(m_Infos.ID, szName, OBJPROP_COLOR, cor); ObjectSetInteger(m_Infos.ID, szName, OBJPROP_SELECTABLE, false); ObjectSetInteger(m_Infos.ID, szName, OBJPROP_SELECTED, false); ObjectSetInteger(m_Infos.ID, szName, OBJPROP_ZORDER, zOrder); }
この関数はチャート上に表示するオブジェクトを作成するための一般的な関数になります。いくつかのケースでは、宣言された要素が2つだけのコード内に表示されることがあります。要素がデフォルト値で宣言されているため、何らかの理由で値が異なることが判明しない限り、呼び出し時に宣言する必要がないためです。さらに、関数が宣言内に2つの要素を使用して呼び出されていることが常にわかります。重要なのは、OBJPROP_ZORDERオブジェクトのこのプロパティは、いくつかの時点で発生する問題を解決するために使用されるということです。このプロパティを正しく定義しないと、リプレイ/シミュレーション、デモ口座またはライブ口座での取引など、どのモードでもプログラムを操作するときに、銘柄 チャート上に配置されたオブジェクトに重大な問題が発生します。メインコードがどのように変更されたかを確認し、元のコードを単に使用するのとは異なる方法でシステムを使用する方法を理解しました。詳細については、別のトピックで説明します。
最初の方法:継承の使用
最初の方向では、C_Mouseクラスからではなく、前の記事で説明したC_Studyクラスからの継承を使用します。ヘッダー ファイルC_StudyS2.mqhには次のコードが含まれます。
//+------------------------------------------------------------------+ #include "C_StudyS1.mqh" //+------------------------------------------------------------------+ // ... Local definitions .... //+------------------------------------------------------------------+ // ... Local alias ... //+------------------------------------------------------------------+ class C_StudyS2 : public C_StudyS1 { protected: private : // ... Code and internal functions ... //+------------------------------------------------------------------+ public : //+------------------------------------------------------------------+ C_StudyS2(C_Mouse *arg, color corP, color corN) :C_StudyS1(arg, corP, corN) { // ... Internal code .... } //+------------------------------------------------------------------+ virtual void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) { double v1, v2; int w, h; string sz1; C_StudyS1::DispatchMessage(id, lparam, dparam, sparam); // ... Internal code ... } //+------------------------------------------------------------------+ };
ここでは、前の記事のクラスが継承の原則に従って使用されており、クラスを継承してプロパティを追加していることがわかります。多くの場合、これが最善の選択肢になりますが、常にそうとは限りません。これらの方向がどのように異なり、相互に補完し合うかを知ることが重要です。したがって、この方法を使用することで、最大限の効果を得ることができます。上記の抜粋で強調表示されているすべての点にご注意ください。心配無用です。興味深いものを作成するためにこれを使用する方法を説明します。
継承を使用しているため、この場合のEA、指標、またはスクリプトコードは、当然、継承を使用しない場合とは若干異なります。これらの違いを理解するために、まずこの最初のケースの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.30" #property icon "../../Images/Icons/Replay - EA.ico" #property link "https://www.mql5.com/ja/articles/11372" //+------------------------------------------------------------------+ #include <Market Replay\System EA\Auxiliar\C_Mouse.mqh> #include <Market Replay\System EA\Auxiliar\Study\C_StudyS2.mqh> //+------------------------------------------------------------------+ input group "Mouse"; input color user00 = clrBlack; //Price Line input color user01 = clrPaleGreen; //Positive Study input color user02 = clrLightCoral; //Negative Study //+------------------------------------------------------------------+ C_Mouse *mouse = NULL; C_StudyS2 *extra = NULL; //+------------------------------------------------------------------+ int OnInit() { mouse = new C_Mouse(user00, user01, user02); extra = new C_StudyS2(mouse, user01, user02); MarketBookAdd((*mouse).GetInfoTerminal().szSymbol); OnBookEvent((*mouse).GetInfoTerminal().szSymbol); EventSetMillisecondTimer(500); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { MarketBookRelease((*mouse).GetInfoTerminal().szSymbol); EventKillTimer(); delete extra; delete mouse; } //+------------------------------------------------------------------+ void OnTick() {} //+------------------------------------------------------------------+ void OnTimer() { (*extra).Update(); } //+------------------------------------------------------------------+ void OnBookEvent(const string &symbol) { MqlBookInfo book[]; if (mouse.GetInfoTerminal().szSymbol == def_SymbolReplay) ArrayResize(book, 1, 0); else { if (symbol != (*mouse).GetInfoTerminal().szSymbol) return; MarketBookGet((*mouse).GetInfoTerminal().szSymbol, book); } (*extra).Update(book); } //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { (*mouse).DispatchMessage(id, lparam, dparam, sparam); (*extra).DispatchMessage(id, lparam, dparam, sparam); ChartRedraw(); } //+------------------------------------------------------------------+
前回の記事のコードとの違いは、強調表示されている部分のみです。継承システムを使用しているためです。すでにご存知のとおり、継承システムは、システムをスムーズに、多くの予期せぬ出来事を起こさずに開発したい場合に非常にうまく機能します。しかし、物事を困難にする他の問題に遭遇することになるかもしれません。場合によっては、アプリケーションで利用できる、少し異なる方法を使用する必要があります。システムを継承ベースのモデルとして使用したい場合は、問題ありません。メモした変更を忘れずにおこなうだけで、すべてがスムーズに進みます。
2つ目の方法:ポインタの使用
この2つ目の方向では、クラスコードの詳細な説明が示されています。まず、EAコードがどのようなものかを見てみましょう。この段階では、クラスコードに大きな違いがありますが、実際には、前のトピックで示した内容によってのみ補完されます。2つ目の方向に従う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.30" #property icon "../../Images/Icons/Replay - EA.ico" #property link "https://www.mql5.com/ja/articles/11372" //+------------------------------------------------------------------+ #include <Market Replay\System EA\Auxiliar\C_Mouse.mqh> #include <Market Replay\System EA\Auxiliar\Study\C_StudyS1.mqh> #include <Market Replay\System EA\Auxiliar\Study\C_StudyS2.mqh> //+------------------------------------------------------------------+ input group "Mouse"; input color user00 = clrBlack; //Price Line input color user01 = clrPaleGreen; //Positive Study input color user02 = clrLightCoral; //Negative Study //+------------------------------------------------------------------+ C_Mouse *mouse = NULL; C_StudyS1 *extra1 = NULL; C_StudyS2 *extra2 = NULL; //+------------------------------------------------------------------+ int OnInit() { mouse = new C_Mouse(user00, user01, user02); extra1 = new C_StudyS1(mouse, user01, user02); extra2 = new C_StudyS2(mouse, user01, user02); MarketBookAdd((*mouse).GetInfoTerminal().szSymbol); OnBookEvent((*mouse).GetInfoTerminal().szSymbol); EventSetMillisecondTimer(500); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { MarketBookRelease((*mouse).GetInfoTerminal().szSymbol); EventKillTimer(); delete extra1; delete extra2; delete mouse; } //+------------------------------------------------------------------+ void OnTick() {} //+------------------------------------------------------------------+ void OnTimer() { (*extra1).Update(); } //+------------------------------------------------------------------+ void OnBookEvent(const string &symbol) { MqlBookInfo book[]; if ((*mouse).GetInfoTerminal().szSymbol == def_SymbolReplay) ArrayResize(book, 1, 0); else { if (symbol != (*mouse).GetInfoTerminal().szSymbol) return; MarketBookGet((*mouse).GetInfoTerminal().szSymbol, book); } (*extra1).Update(book); } //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { (*mouse).DispatchMessage(id, lparam, dparam, sparam); (*extra1).DispatchMessage(id, lparam, dparam, sparam); (*extra2).DispatchMessage(id, lparam, dparam, sparam); ChartRedraw(); } //+------------------------------------------------------------------+
ここでは、黄色でマークされたメインクラスシステムを使用する場所を示しています。前回の記事で示した拡張クラスシステムは緑色でマークされています。別のタイプの分析を実行するシステム(別のものである可能性もある)はオレンジ色で示されています。継承を使用していないため、EAでさらに多くのコードを宣言する必要があります。同時に、これにより、最終バージョンでどのようなものになるかをテストするために、より多くの並列コードをリリースすることができます。最も良い点は、この並列コードに誤動作やエラーが発生し始めた場合、それほど苦労せずにコードから削除できることです。ただし、ここには別の問題があります。オレンジ色のコードと緑色のコードは両方ともポリモーフィックになる可能性があります。これにより、並行して開発されているシステムのより多くの側面をテストできるようになります。ポリモーフィズムの話題は別の機会に譲ります。今それについて話すと、説明が複雑になりすぎて、愛好家が実際にポリモーフィズムの使用の背後にあるすべての推論に従うことができない可能性があります。
クラスコードには、これらの説明の後進むことができます。最初の方向と2つ目の方向のコードは、最初の方向に関するトピックで示されている点を除いて、ほぼ同じであることにご注意ください。
C_StudyS2クラスのコードを分析してみましょう
ある意味、分析システムに関連付けられたすべてのコードは、いくつかの例外を除いて、互いに非常によく似ています。ただし、分析生成コードを分析して理解するのに興味深い点がいくつかあります。これを詳しく見てみましょう。ここで提供されるコードはデモンストレーションのみを目的としており、決して完全な方法ではないことにご注意ください。C_StudyS2.mqhの始まりは次のとおりです。
#property copyright "Daniel Jose" //+------------------------------------------------------------------+ #include "..\C_Mouse.mqh" #include "..\..\..\Service Graphics\Support\Interprocess.mqh" //+------------------------------------------------------------------+ #define def_ExpansionPrefix "Expansion2_" #define def_ExpansionBtn1 def_ExpansionPrefix + "B1" #define def_ExpansionFibo def_ExpansionPrefix + "FB" //+------------------------------------------------------------------+ #define def_InfoTerminal (*mouse).GetInfoTerminal() #define def_InfoMousePos (*mouse).GetInfoMouse().Position //+------------------------------------------------------------------+ class C_StudyS2 { protected: private : //+------------------------------------------------------------------+ C_Mouse *mouse; //+------------------------------------------------------------------+ struct st00 { bool ExecStudy, ClearStudy; double MemPrice; datetime MemDT; color corP, corN; }m_Info; //+------------------------------------------------------------------+
ここで、システムに含める必要があるファイルを宣言します。方向は、この C_StudyS2.mqh ファイルが配置されている方向を基準にして表示されていることにご注意ください。これにより、プロジェクトの構造を維持しながら、プロジェクトを他のディレクトリに簡単に移動できるようになります。次に、調査プロセスで使用するいくつかのオブジェクト名を定義します。コードの作成中にさまざまな場所で使用されるため、プログラミングプロセスを容易にするためのエイリアス宣言もあります。このフラグメントで最後に確認できるのは、private グローバル変数を介してアクセスされる構造体です。
次のコード部分は次のとおりです。
#define def_FontName "Lucida Console" #define def_FontSize 10 void GetDimensionText(const string szArg, int &w, int &h) { TextSetFont(def_FontName, -10 * def_FontSize, FW_NORMAL); TextGetSize(szArg, w, h); h += 5; w += 5; } //+------------------------------------------------------------------+ void CreateBTNInfo(int x, int w, int h, string szName, color backColor) { (*mouse).CreateObjectGraphics(szName, OBJ_BUTTON, clrNONE); ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_STATE, true); ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_BORDER_COLOR, clrBlack); ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_COLOR, clrBlack); ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_BGCOLOR, backColor); ObjectSetString(def_InfoTerminal.ID, szName, OBJPROP_FONT, def_FontName); ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_FONTSIZE, def_FontSize); ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(def_InfoTerminal.ID, szName, OBJPROP_XDISTANCE, x); } #undef def_FontSize #undef def_FontName
ここには、この場所でのみ使用される2つの宣言があるため、コードの残りの部分で必要がなくなったらすぐに定義を定義して削除します。この時点で、チャート上で使用するオブジェクトを作成する関数をすでに呼び出しています。タスクは、オブジェクトを作成し、そのプロパティの一部を調整して、希望どおりに構築できるようにすることです。ただし、お気づきかと思いますが、ボタンは読み取り専用のテキストを含むウィンドウであるかのように使用されています。おそらく、ここではOBJ_LABELまたはOBJ_EDITを使用する方が適切でしょう。ただし、ここでは、最適な結果を達成する方法の1つを示すことについてのみ話しています。したがって、別のオブジェクトを使用してデータをチャートに配置できます。
このクラスの優れている点は、それに含まれる2つの関数です。最初のものを以下に示します。もう1つについては、この記事の最後で説明します。次に、ビデオ01で示されている、フィボナッチオブジェクトを使用した分析をこのクラスがどのように作成するかを見てみましょう。このオブジェクトを作成するコードを以下に示します。
void CreateStudy(void) { const double FiboLevels[] = {0, 0.236, 0.382, 0.50, 0.618, 1, 1.618, 2}; ENUM_LINE_STYLE ls; color cor; ObjectDelete(def_InfoTerminal.ID, def_ExpansionFibo); ObjectDelete(def_InfoTerminal.ID, "MOUSE_TB"); ObjectDelete(def_InfoTerminal.ID, "MOUSE_TI"); ObjectDelete(def_InfoTerminal.ID, "MOUSE_TT"); (*mouse).CreateObjectGraphics(def_ExpansionFibo, OBJ_FIBO, clrNONE); ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionFibo, OBJPROP_HIDDEN, false); ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionFibo, OBJPROP_RAY_LEFT, false); ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionFibo, OBJPROP_LEVELS, ArraySize(FiboLevels)); for (int c0 = 0, c1 = ArraySize(FiboLevels); c0 < c1; c0++) { ls = ((FiboLevels[c0] == 0) || (FiboLevels[c0] == 1) || (FiboLevels[c0] == 2) ? STYLE_SOLID : STYLE_DASHDOT); ls = (FiboLevels[c0] == 0.5 ? STYLE_DOT : ls); switch (ls) { case STYLE_DOT : cor = clrBlueViolet; break; case STYLE_DASHDOT: cor = clrViolet; break; default : cor = clrIndigo; } ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionFibo, OBJPROP_LEVELSTYLE, c0, ls); ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionFibo, OBJPROP_LEVELCOLOR, c0, cor); ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionFibo, OBJPROP_LEVELWIDTH, c0, 1); ObjectSetString(def_InfoTerminal.ID, def_ExpansionFibo, OBJPROP_LEVELTEXT, c0, (string)NormalizeDouble(FiboLevels[c0] * 100, 2)); } ObjectSetDouble(def_InfoTerminal.ID, def_ExpansionFibo, OBJPROP_PRICE, 1, m_Info.MemPrice = def_InfoMousePos.Price); ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionFibo, OBJPROP_TIME, 1, m_Info.MemDT = def_InfoMousePos.dt); CreateBTNInfo(def_InfoMousePos.X, 50, 18, def_ExpansionBtn1, clrNONE); m_Info.ExecStudy = true; m_Info.ClearStudy = false; }
このコードは一見複雑に見えるかもしれませんが、実際には3つの部分で構成されています。これらの各部分では、OBJ_FIBOを使用して特定の分析を実行します。
- 最初の部分では、ユーザーが銘柄 チャートの分析を開始したことを示すイベントをプラットフォームから受信したときに、C_Mouseクラスによって作成された「不要な」オブジェクトを削除しました。これらのオブジェクトを削除するときは、本当に重要なものを削除しないようにご注意ください。したがって、ここで作成する調査から見る必要のないものをすべて削除することで、非常に特殊な分析を作成できます。古い分析のオブジェクトを削除しました。特定の基準に基づいて分析を実行できるようにするためにです。この理由は、キーの組み合わせを使用してOBJ_FIBOのバリエーションに基づいた分析を作成したいことも考えられます。これらのバリエーションには、OBJ_FIBOTIMES、OBJ_FIBOFAN、OBJ_FIBOARC、OBJ_FIBOCHANNEL、OBJ_EXPANSIONがあります。これらはすべて、ここで示す同じ原則に従います。
- 2つ目の部分では、オブジェクトのプロパティを作成して定義します。以下に興味深い点をいくつか示します。この段階で、オブジェクトがオブジェクトのリストに表示されることをプラットフォームに伝えます。ここでは、オブジェクトにどのレベルが含まれるかを指定します。ここでは静的レベルを使用しましたが、システムでは動的レベルや他のレベルを使用することもできます。このセクションで。すべてのレベルがどのようなものになるのか、色とレベルの構築に使用される線の形式の両方で説明します。分析をおこなうときは、分析から利益を得るためにすぐに理解したいため、適切な表現を取得するために独自の裁量で変更を加えることができます。
- そして最後の3つ目の部分では、チャート上にオブジェクトを直接構築し始めます。つまり、プロットを開始します。変数で何が起こるかも見ていきます。これは、後で説明する関数中にすべてが正しくおこなわれるために必要です。
基本的に、この方法で、C_Mouseクラスにあるすでに作成されテストされたシステムに基づいて研究を作成します。言い換えれば、何かをゼロから構築するのではなく、何か異なるものを達成するためにすでに持っているものを再利用し、適応させるつもりです。2つ目のプロシージャを検討すると、すべてが明らかになります。次に、クラスのコンストラクタとデストラクタを見てみましょう。以下で確認できます。
C_StudyS2(C_Mouse *arg, color corP, color corN) { mouse = arg; ZeroMemory(m_Info); m_Info.corP = corP; m_Info.corN = corN; } //+------------------------------------------------------------------+ ~C_StudyS2() { ObjectsDeleteAll(def_InfoTerminal.ID, def_ExpansionPrefix); }
これら2つの関数をよく見てください。目標は、2つ目の方法に基づいたシステムを使用することです。継承モデルを使用するには、最初の方向 トピックで使用されている行を追加する必要があります。クラスの最後の関数でも同じことをおこなう必要があります。この部分により、プラットフォームとの対話が可能になります。以下は、実際に分析を作成できる関数の完全なコードです。
virtual void DispatchMessage(const int id, const long &lparam, const double &dparam, const string &sparam) { double v1, v2; int w, h; string sz1; switch (id) { case CHARTEVENT_KEYDOWN: if (TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE) && (m_Info.ExecStudy)) m_Info.ClearStudy = true; break; case CHARTEVENT_MOUSE_MOVE: if (mouse.GetInfoMouse().ExecStudy) { if (!m_Info.ExecStudy) CreateStudy(); v1 = def_InfoMousePos.Price - m_Info.MemPrice; v2 = MathAbs(100.0 - ((m_Info.MemPrice / def_InfoMousePos.Price) * 100.0)); sz1 = StringFormat(" %." + (string)def_InfoTerminal.nDigits + "f [ %d ] %02.02f%% ", MathAbs(v1), Bars(def_InfoTerminal.szSymbol, PERIOD_CURRENT, m_Info.MemDT, def_InfoMousePos.dt) - 1, v2); GetDimensionText(sz1, w, h); ObjectSetDouble(def_InfoTerminal.ID, def_ExpansionFibo, OBJPROP_PRICE, 0, def_InfoMousePos.Price); ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionFibo, OBJPROP_TIME, 0, def_InfoMousePos.dt); ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionFibo, OBJPROP_COLOR, (v1 < 0 ? m_Info.corN : m_Info.corP)); ObjectSetString(def_InfoTerminal.ID, def_ExpansionBtn1, OBJPROP_TEXT, sz1); ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionBtn1, OBJPROP_BGCOLOR, (v1 < 0 ? m_Info.corN : m_Info.corP)); ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionBtn1, OBJPROP_XSIZE, w); ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionBtn1, OBJPROP_YSIZE, h); ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionBtn1, OBJPROP_XDISTANCE, def_InfoMousePos.X - w); ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionBtn1, OBJPROP_YDISTANCE, def_InfoMousePos.Y - (v1 < 0 ? 1 : h)); }else if (m_Info.ExecStudy) { ObjectSetInteger(def_InfoTerminal.ID, def_ExpansionFibo, OBJPROP_COLOR, clrNONE); ObjectDelete(def_InfoTerminal.ID, def_ExpansionBtn1); if (m_Info.ClearStudy) ObjectDelete(def_InfoTerminal.ID, def_ExpansionFibo); m_Info.ExecStudy = false; } break; } }
とても興味深いコードだと思いませんか。マウス操作を考慮していないことにご注意ください。ここでは C_Mouseクラスが何をしているかだけを見ていきます。C_Mouseクラスは分析をおこなっていることを示しますが、このクラスはその指示に従い、C_Mouseクラスの指示に従って分析を実行します。C_Mouseクラスが分析で使用されなくなったら、情報テキストをホストするために使用されたオブジェクトを削除します。解析中にESCキーを押すと、解析対象も削除されます。テキストの表示に使用されるオブジェクトのサイズは動的に計算されます。つまり、場合に応じて大きくなったり小さくなったりする可能性があり、これらすべてがこのコードで制御されます。ここでは、色とオブジェクトの配置も制御します。
このコードには、さらに説明する価値のある興味深い部分があります。次に見てみましょう。私たちは何を表すのか、そしてなぜこれらの値が使用されるのかを理解する必要があります。
v1 = def_InfoMousePos.Price - m_Info.MemPrice; v2 = MathAbs(100.0 - ((m_Info.MemPrice / def_InfoMousePos.Price) * 100.0)); sz1 = StringFormat(" %." + (string)def_InfoTerminal.nDigits + "f [ %d ] %02.02f%% ", MathAbs(v1), Bars(def_InfoTerminal.szSymbol, PERIOD_CURRENT, m_Info.MemDT, def_InfoMousePos.dt) - 1, v2);
プレゼンテーション用に情報を因数分解してフォーマットするこれらの3行を理解するには、コードが実行されている銘柄にシステムが動的に適応することを確認する必要があります。値を表すために 4 文字を必要とする銘柄もあれば、5文字を必要とする銘柄もあります。一部の株式商品には2文字しかありません。システムを簡単に適応できるようにするために、上記のコードを使用します。奇妙に聞こえますが、実際には単に珍しいだけです。
まず、分析を開始した価格と価格線の差を考慮します。これにより、ポイントまたは財務的価値で価値が提供されます。これは、解析を開始した位置とマウスの現在の位置の間のオフセット値です。これを正しく表現するには、必要な文字数を知る必要があります。これをおこなうには、次の方法を使用します。パーセント記号(%)を使用すると、文字列に変換される情報の種類を定義できます。次の形式< %.2f>の場合は小数点以下2桁を含む値が取得され、<%.4f>の場合は小数点以下4桁を含む値が取得されます。ただし、これを実行時に定義する必要があります。
StringFormat関数は、適切な形式自体を作成します。わかりにくいかもしれませんが、差分を使用して計算した値が配置されると、作成した形式に従って正確に配置されます。これにより、表示された値に対応する小数点以下の桁数が得られます。これが実際にどのように機能するかを理解するには、より明確にするために、異なる文字数の資産で同じコードを使用する必要があります。もう1つの問題は、特定の点からのバーの数を簡単な方法で調べることです。
一部のプラットフォームでは、バーをカウントしてチャート上に表示する指標が提供されています。このような指標は簡単に作成できます。しかし同時に、チャート上に表示される情報がますます増え、膨大な量の情報で埋め尽くされてしまい、そのほとんどが不必要であることが多くなり、読みにくくなることがよくあります。少し変わった方法で MQL5 言語を使用すると、分析領域にあるバーの数を計算し、この値をリアルタイムでチャート上に直接表示できます。分析が完了すると、必要な情報だけがチャートに残ります。
このような分析をおこなうために、この関数をこれらのパラメータとともに使用します。ただし、バーのない領域で分析を実行した場合、表示値は-1になり、1本のバーで分析を実行した場合、値は0になるのでご注意ください。バーの数は分析中の領域に存在するバーの数を参照するため、これを変更するには、単純に因数分解からこの値-1を削除します。したがって、値は常に、分析が開始されたバーを含む実際のバーの数に対応します。このため、分析で値が-1になる場合があります。
表示に偏差の割合も報告したいので、この計算を使用してこの割合を取得します。視覚化をよりわかりやすくするために、この形式を使用して、残りの情報とともにパーセント記号を表示できるようにします。
結論
ここでは、プロのプログラミングのさまざまな時点で非常に役立つテクニックを紹介しました。多くの人が考えているのとは反対に、制限されているのはプラットフォーム自体ではなく、そのプラットフォームや言語ではさまざまなものを作成できないと主張する人々の知識であることを示しました。ここで説明したことによって、常識と創造性があれば、MetaTrader 5プラットフォームをより面白く、多用途にすることができることがわかります。クレイジーなプログラムなどを作成する必要もありません。シンプルで安全、信頼性の高いコードを作成できます。創造力を発揮して、ソース コードを1行も削除したり追加したりすることなく、既存のコードを変更できます。ある時点で、しばらく使用してきたコードが本当に役立つようになった場合は、そのコードを継続的かつ簡単に堅牢なコードに追加できます。クラスの概念が使用されるのはこのためです。クラスでは、コード継承階層が単純に作成されます。
出来ない仕事はありません。人によっては出来ない仕事もあります。しかし、これはタスクを実行できないという意味ではありません。
添付ファイルには、これらの記事全体で作成した完全なコードが含まれています。次の部分では、分析コードを除いて、このシステムを詳しく見ていきます。おそらくその一部はC_Mouseクラスに組み込まれるでしょうが、組み込まれた場合、すべてのコードは以前の記事で説明されているため、詳細には説明しません。また近いうちにお会いしましょう。
MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/11372
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索