単一チャート上の複数インジケータ(第05部):MetaTrader 5をRADシステムに変える(I)
はじめに
プログラミングはできなくても創造性に富んだ素晴らしいアイデアを持っている人はたくさんいます。しかし、プログラミングの知識がないため、これらのアイデアを実行に移すことができないのです。今日は、成行注文を送信したり、指値注文で使用するパラメータを設定したりするための独自のChart Tradeインターフェイスを作成します。作成にはEAの中に配置される関数を使うだけで、プログラミングはしません。気になるので、モニターでどのように見えるか見てみましょう。
しかし、やり方の見当がつかず、プログラミングのことを何も知らない自分の知識だけでは無理だと思われるかもしれません。 上の画像にあるChart Tradeは、MetaTrader 5プラットフォームだけで作成されており、下の画像のように設計されました。
この記事の内容を理解した今、私たちは自分のチャートを作成する熱意とアイデアに満ち溢れているはずです。ただし、それを実現するためには、いくつかのステップをクリアする必要があります。補助コードを設定すれば、独自のChart Trade IDEを設計する唯一の制限は私たちの創造性です。この記事は連載の続きなので、完全かつ包括的に理解するためには、連載の過去の記事を読むことをお勧めします。
では、さっそく仕事に取りかかりましょう。
計画
まず初めに、IDEとして使用するチャートのプロパティを編集します。これは、潜在的な副作用を軽減するためにおこなわれます。重要なのは、チャートをクリーンなままにしておくことで、Chart Tradeインターフェイスの構築と設計がより簡単になるということです。チャートのプロパティを開き、次の図に示すようにプロパティを設定します。
画面は完全にクリーンになり、IDEの開発を妨げる可能性のあるものがすべてなくなります。では、次の説明に注目してください。IDEは設定ファイル(TEMPLATE)として保存されるので、MetaTrader 5が提供するあらゆるオブジェクトを使用できますが、実用上の理由からその一部のみを使用することにします。利用可能なすべてのオブジェクトについては、 MetaTrader 5のオブジェクト型をご覧ください。
オブジェクト | 位置決めに使用する座標の種類 | IDEに重要? |
---|---|---|
テキスト | 日付と価格 | いいえ |
ラベル | XおよびYの位置 | はい |
ボタン | XおよびYの位置 | はい |
チャート | XおよびYの位置 | はい |
ビットマップ | 日付と価格 | いいえ |
ビットマップラベル | XおよびYの位置 | はい |
編集 | XおよびYの位置 | はい |
イベント | 日付のみ使用 | いいえ |
長方形ラベル | XおよびYの位置 | はい |
画面のどの領域にも配置できるシステムを使用します。X座標系とY座標系を使用しないオブジェクトを使用すると、IDEが完全に異なって見える可能性があるため、実用的ではありません。したがって、システムでのオブジェクトを6つに制限します。これは、インターフェイスを作成するのに十分な数です。
アイデアは、画面上に何かを描くときと同じように、論理的な順序でオブジェクトを配置することです。まず背景を作成し、次にオブジェクトを重ねて配置し、インターフェイスを開発しながらオブジェクトを配置および調整します。それはこのように見えます。
このように、IDEを設計して作成する方法はとてもシンプルで、少し練習すれば習得できます。ここでの考え方は、コードによるユーザーインターフェイスの開発が非常に複雑になる場合に、プログラミングインターフェイスを作成するために使われるRADプログラムと非常によく似ています。コードを使用して直接インターフェイスを作成できないわけではありません。しかし、この方法を使うことで、さらなる改造がより早く、より簡単になるので、自分のスタイルに合ったインターフェイスを求める人には最適な方法です。
完成すれば、以下のようなインターフェイスになるかもしれませんし、もっとクールなものになるかもしれません。ただし、ここでは、できるだけ多くのオブジェクトを使用して、試してみることができるようにしました。自分好みのインターフェイスを作ることができます。
これは、IDEを作成するための最初のステップです。次に、このインターフェイスを実際にサポートして機能させるコードを作成する必要があります。独自のユーザーインターフェイスを作成できるという単純な事実も動機の源であるはずですが、この動機はコードに具体化されます。
次のステップは、このインターフェイスを設定ファイルとして保存することです。そうすれば、前のバージョンのコードを使用して参照として表示できます。つまり、ソースコードに大きな変更を加える必要がなくなります。ただし、IDEでのイベントの送受信が可能かどうかをテストしたいとすれば、これが不可能であることがわかるでしょう。しかし、インターフェースがMetaTrader 5のオブジェクトを使用して作成された場合、これらのオブジェクトとの間でイベントを送受信できないのはなぜでしょうか。この質問への答えは、説明するよりも示す方が簡単です。EAの元のバージョンに次のコードを追加することで確認できます。
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { switch (id) { case CHARTEVENT_OBJECT_CLICK: Print(sparam); break; // .... The rest of the code... } }
このコードでは、クリックを受けたオブジェクトの名前を報告し、イベントを発生させます。この場合、イベントはCHARTEVENT_OBJECT_CLICKとなります。ただし、出力されるメッセージは、IDE内のオブジェクトの名前ではなく、EAによって作成されたオブジェクトの名前になります。これはIDEを使えなくする大きな問題のように思えますが、非常に簡単な解決策があります。設定ファイルを読み込んで、このファイルで指定されたとおりにオブジェクトを作成するのです。これでチャートの上でIDEが作成されます。設定ファイル(TPL)を解析することで、必要なデータを探し出すことができます。
キー | 詳細 |
---|---|
<chart> | 設定ファイルを起動する |
</chart> | 設定ファイルを終了する |
<window> | チャート上に存在する要素の構造を開始する |
</window> | チャート上に存在する要素の構造をを終了する |
<indicator> | ある指標に関連するデータを提供する構造を開始する |
</indicator> | ある指標に関連するデータを提供する構造を終了する |
<object> | あるオブジェクトに関するデータを提供する構造を開始する |
</object> | オブジェクトデータを提供する構造体を終了する |
この構造は、TPLファイル内部では次のようになります。
<chart> .... DATA <window> ... DATA <indicator> ... DATA </indicator> <object> ... DATA </object> </window> </chart>
関心のある部分は、<object>と</object>の間にあります。このような構造は複数存在し、それぞれが固有のオブジェクトを示すことができます。したがって、まず、ファイルの場所を変更する必要があります。読み取りできる場所に追加するべきです。これがFILESディレクトリです。場所を変更することは可能ですが、いずれにしてもファイルはFILEツリーの中になければなりません。
重要:IDEの設定ファイルを使用する際に、チャートをクリアできるようにシステムを修正しましたが、Profiles\Templatesディレクトリにっも同名のクリーンなファイルを用意するのが理想的です。これにより、以前の記事で見たように、デフォルトのテンプレートに残り物が存在するのを最小限に抑えることができます。主な変更点は以下で強調表示されています。
#include <Auxiliar\Chart IDE\C_Chart_IDE.mqh> //+------------------------------------------------------------------+ class C_TemplateChart : public C_Chart_IDE { .... Other parts from code .... //+------------------------------------------------------------------+ void AddTemplate(const eTypeChart type, const string szTemplate, int scale, int iSize) { if (m_Counter >= def_MaxTemplates) return; if (type == SYMBOL) SymbolSelect(szTemplate, true); SetBase(szTemplate, (type == INDICATOR ? _Symbol : szTemplate), scale, iSize); if (!ChartApplyTemplate(m_handle, szTemplate + ".tpl")) if (type == SYMBOL) ChartApplyTemplate(m_handle, "Default.tpl"); if (szTemplate == "IDE") C_Chart_IDE::Create(m_IdSubWin); ChartRedraw(m_handle); } //+------------------------------------------------------------------+ void Resize(void) { #define macro_SetInteger(A, B) ObjectSetInteger(Terminal.Get_ID(), m_Info[c0].szObjName, A, B) int x0 = 0, x1, y = (int)(ChartGetInteger(Terminal.Get_ID(), CHART_HEIGHT_IN_PIXELS, m_IdSubWin)); x1 = (int)((ChartGetInteger(Terminal.Get_ID(), CHART_WIDTH_IN_PIXELS, m_IdSubWin) - m_Aggregate) / (m_Counter > 0 ? (m_CPre == m_Counter ? m_Counter : (m_Counter - m_CPre)) : 1)); for (char c0 = 0; c0 < m_Counter; x0 += (m_Info[c0].width > 0 ? m_Info[c0].width : x1), c0++) { macro_SetInteger(OBJPROP_XDISTANCE, x0); macro_SetInteger(OBJPROP_XSIZE, (m_Info[c0].width > 0 ? m_Info[c0].width : x1)); macro_SetInteger(OBJPROP_YSIZE, y); if (m_Info[c0].szTemplate == "IDE") C_Chart_IDE::Resize(x0); } ChartRedraw(); #undef macro_SetInteger } //+------------------------------------------------------------------+ ... The rest of the code }
IDEインターフェイスは新しいクラスとして追加され、元のクラスに継承されています。つまり、元のクラスの機能が拡張されることになり、元のコードに副作用が発生することはありません。
ここまでは簡単な部分です。次に、IDEをサポートするために、より複雑なことをおこなう必要があります。まず、システムが使用するメッセージプロトコルを作成します。このプロトコルにより、システムは以下のように動作するようになります。
なお、現在は不可能ですが、メッセージプロトコルを追加することで、システムデータを変更し、IDEを機能させることが可能になります。それでは、いくつかのことを定義しましょう。
メッセージ | 用途 |
---|---|
MSG_BUY_MARKET | 成行買い注文を出す |
MSG_SELL_MARKET | 成行売り注文を出す |
MSG_LEVERAGE_VALUE | データを活用する |
MSG_TAKE_VALUE | 取引のテイクプロフィットデータ |
MSG_STOP_VALUE | 取引のストップロスデータ |
MSG_RESULT | 現在のポジションの結果に関するデータ |
MSG_DAY_TRADE | その日の終わりに取引を終了するかどうかを通知する |
このプロトコルは、とても重要なステップです。定義後は、設定ファイルに変更を加えます。オブジェクトのリストを開いたら、次のように変更します。
ここで示しているインターフェイスには、画像のようなオブジェクトのリストがあります。以下の事実にご注目ください。オブジェクトのNAMEは、使用する各メッセージに対応しています。他のオブジェクトの名前は、IDEのモデリングに役立てるので問題ありませんが、メッセージの名前を持つオブジェクトは、メッセージを送受信します。より多くのメッセージや異なるタイプのメッセージを使用したい場合は、クラスコードに必要な変更を加えるだけで、IDEとEAコードの間でメッセージを交換する手段はMetaTrader 5自体で提供されます。
しかし、オブジェクトクラスの作成方法を知るためには、まだTPLファイルについて調べる必要があります。それでは、TPLファイル内でオブジェクトがどのように宣言されているかを見てみましょう。ターミナルのインターフェイス自体がオブジェクトプロパティへのアクセスを少なくしているため、プログラミングよりもTPLファイルのオブジェクトプロパティへのアクセスが少なくなることは事実です。しかし、そのアクセスでも十分にIDEを機能させることができるでしょう。
つまり、TPLファイルの中には、<object>と</object>の間に、必要な構造があります。構造の中のデータから。どのような種類のオブジェクトであるかを調べる方法が不明確に思えるかもしれません。しかし、よく見てみると、オブジェクトの型は type変数で特定できることがわかります。これは、オブジェクトごとに異なる値をとります。下の表は、使用したいオブジェクトを示したものです。
TYPE変数の値 | 参照されるオブジェクト |
---|---|
102 | OBJ_LABEL |
103 | OBJ_BUTTON |
106 | OBJ_BITMAP_LABEL |
107 | OBJ_EDIT |
110 | OBJ_RECTANGLE_LABEL |
クラスには、すでに形ができ始めています。次は1つ目の関数コードです。
bool Create(int nSub) { m_CountObject = 0; if ((m_fp = FileOpen("Chart Trade\\IDE.tpl", FILE_BIN | FILE_READ)) == INVALID_HANDLE) return false; FileReadInteger(m_fp, SHORT_VALUE); for (m_CountObject = eRESULT; m_CountObject <= eEDIT_STOP; m_CountObject++) m_ArrObject[m_CountObject].szName = ""; m_SubWindow = nSub; m_szLine = ""; while (m_szLine != "</chart>") { if (!FileReadLine()) return false; if (m_szLine == "<object>") { if (!FileReadLine()) return false; if (m_szLine == "type") { if (m_szValue == "102") if (!LoopCreating(OBJ_LABEL)) return false; if (m_szValue == "103") if (!LoopCreating(OBJ_BUTTON)) return false; if (m_szValue == "106") if (!LoopCreating(OBJ_BITMAP_LABEL)) return false; if (m_szValue == "107") if (!LoopCreating(OBJ_EDIT)) return false; if (m_szValue == "110") if (!LoopCreating(OBJ_RECTANGLE_LABEL)) return false; } } } FileClose(m_fp); return true; }
まず、ファイルを読み取りモードでバイナリファイルとして開きます。これは、見落としがないようにするためです。HEXAエディタを使用した場合、TPLファイルは以下のようになります。非常に興味深い値で始まります。
わかりにくいと思われるかもしれませんが、実は、そうではないのです。このファイルでは、UTF-16エンコードを使用しています。データは行単位で整理されていることが分かっているので、行全体を一度に読み取る関数を作ってみましょう。そのために、次のようなコードを書いてみます。
bool FileReadLine(void) { int utf_16 = 0; bool b0 = false; m_szLine = m_szValue = ""; for (int c0 = 0; c0 < 500; c0++) { utf_16 = FileReadInteger(m_fp, SHORT_VALUE); if (utf_16 == 0x000D) { FileReadInteger(m_fp, SHORT_VALUE); return true; } else if (utf_16 == 0x003D) b0 = true; else if (b0) m_szValue = StringFormat("%s%c", m_szValue, (char)utf_16); else m_szLine = StringFormat("%s%c", m_szLine, (char)utf_16); if (FileIsEnding(m_fp)) break; } return (utf_16 == 0x003E); }
読み出しをできるだけ効率的にするため、等号(=) が見つかったら、読み出しを続けずにすぐに終了します。ループでは、文字列を最大500文字に制限していますが、この値は任意であり、必要に応じて変更することが可能です。新しい文字列が見つかるたびに、この関数は終了して文字列の内容を提供し、適切な分析を進められるようにします。
メッセージプロトコルをサポートするために、ある種の変数が必要になります。それらは以下のコードに示されています。
class C_Chart_IDE { protected: enum eObjectsIDE {eRESULT, eBTN_BUY, eBTN_SELL, eCHECK_DAYTRADE, eBTN_CANCEL, eEDIT_LEVERAGE, eEDIT_TAKE, eEDIT_STOP}; //+------------------------------------------------------------------+ #define def_HeaderMSG "IDE_" #define def_MaxObject eEDIT_STOP + 32 //+------------------------------------------------------------------+ private : int m_fp, m_SubWindow, m_CountObject; string m_szLine, m_szValue; bool m_IsDayTrade; struct st0 { string szName; int iPosX; }m_ArrObject[def_MaxObject]; // ... The rest of the class code....
def_MaxObjectは、保持できるオブジェクトの最大数を定義しています。この数値は、メッセージの数にこれから使うオブジェクトの数を足したものをもとに求められます。今回は最大40オブジェクトですが、これは必要に応じて変更できます。最初の8オブジェクトは、IDEとMetaTrader 5の間でメッセージを送信するために使用されます。これらのメッセージの別名はeObjectsIDEの列挙で見ることができます。システムを拡張したり、何かに適応させたりする場合には、この点を覚えておくことが重要です。
これはあくまでサポートの仕組みの第一段階です。もうひとつ、メッセージの仕組みを扱う定数に注目したいと思います。実際、MQL5での定数の扱い方は、C/C++でプログラミングしている人には少しわかりにくいかもしれません。C/C++では、定数は変数宣言自体で宣言されます。MQL5では、その作成方法でコードが少し複雑になることがありますが、定数が使われることはほとんどないので、この点は我慢してください。以下にその方法を太字で示します。
public : static const string szMsgIDE[]; // ... The rest of the class code.... }; //+------------------------------------------------------------------+ static const string C_Chart_IDE::szMsgIDE[] = { "MSG_RESULT", "MSG_BUY_MARKET", "MSG_SELL_MARKET", "MSG_DAY_TRADE", "MSG_CLOSE_POSITION", "MSG_LEVERAGE_VALUE", "MSG_TAKE_VALUE", "MSG_STOP_VALUE" }; //+------------------------------------------------------------------+
定義された定数は、インターフェイス内のオブジェクト名で使用されている値と全く同じものです。大文字と小文字は区別されません.。この動作は変更することも可能ですが、あまりお勧めしません。
これらの手順をすべて終えたら、いよいよ次のステップに進みます。TPLファイルに戻って、以下の断片を見てください。
使用するオブジェクトの種類を定義した後、名前、位置、色、フォントなど、オブジェクトのプロパティを示す一連のデータがあります。これらのプロパティは、内部オブジェクトに渡されるべきです。繰り返し作業になるので、そのための一般的な関数を作ればいいのです。以下のようになります。
bool LoopCreating(ENUM_OBJECT type) { #define macro_SetInteger(A, B) ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[c0].szName, A, B) #define macro_SetString(A, B) ObjectSetString(Terminal.Get_ID(), m_ArrObject[c0].szName, A, B) int c0; bool b0; string sz0 = m_szValue; while (m_szLine != "</object>") if (!FileReadLine()) return false; else { if (m_szLine == "name") { b0 = false; StringToUpper(m_szValue); for(c0 = eRESULT; (c0 <= eEDIT_STOP) && (!(b0 = (m_szValue == szMsgIDE[c0]))); c0++); c0 = (b0 ? c0 : m_CountObject); m_ArrObject[c0].szName = StringFormat("%s%04s>%s", def_HeaderMSG, sz0, m_szValue); ObjectDelete(Terminal.Get_ID(), m_ArrObject[c0].szName); ObjectCreate(Terminal.Get_ID(), m_ArrObject[c0].szName, type, m_SubWindow, 0, 0); } if (m_szLine == "pos_x" ) m_ArrObject[c0].iPosX = (int) StringToInteger(m_szValue); if (m_szLine == "pos_y" ) macro_SetInteger(OBJPROP_YDISTANCE , StringToInteger(m_szValue)); if (m_szLine == "size_x" ) macro_SetInteger(OBJPROP_XSIZE , StringToInteger(m_szValue)); if (m_szLine == "size_y" ) macro_SetInteger(OBJPROP_YSIZE , StringToInteger(m_szValue)); if (m_szLine == "offset_x" ) macro_SetInteger(OBJPROP_XOFFSET , StringToInteger(m_szValue)); if (m_szLine == "offset_y" ) macro_SetInteger(OBJPROP_YOFFSET , StringToInteger(m_szValue)); if (m_szLine == "bgcolor" ) macro_SetInteger(OBJPROP_BGCOLOR , StringToInteger(m_szValue)); if (m_szLine == "color" ) macro_SetInteger(OBJPROP_COLOR , StringToInteger(m_szValue)); if (m_szLine == "bmpfile_on" ) ObjectSetString(Terminal.Get_ID() , m_ArrObject[c0].szName, OBJPROP_BMPFILE, 0, m_szValue); if (m_szLine == "bmpfile_off" ) ObjectSetString(Terminal.Get_ID() , m_ArrObject[c0].szName, OBJPROP_BMPFILE, 1, m_szValue); if (m_szLine == "fontsz" ) macro_SetInteger(OBJPROP_FONTSIZE , StringToInteger(m_szValue)); if (m_szLine == "fontnm" ) macro_SetString(OBJPROP_FONT , m_szValue); if (m_szLine == "descr" ) macro_SetString(OBJPROP_TEXT , m_szValue); if (m_szLine == "readonly" ) macro_SetInteger(OBJPROP_READONLY , StringToInteger(m_szValue) == 1); if (m_szLine == "state" ) macro_SetInteger(OBJPROP_STATE , StringToInteger(m_szValue) == 1); if (m_szLine == "border_type" ) macro_SetInteger(OBJPROP_BORDER_TYPE , StringToInteger(m_szValue)); } m_CountObject += (b0 ? 0 : (m_CountObject < def_MaxObject ? 1 : 0)); return true; #undef macro_SetString #undef macro_SetInteger }
各オブジェクトは名前を取得し、適切な場所に保存されますが、強調表示された行は異なるものを示しています。IDEを作成する場合、チャートの左上から開始しなければなりませんが、このXの位置は必ずしもサブウインドウの左上とは限りません。この位置は、IDEがバインドされるOBJ_CHARTオブジェクトの左上隅に対応していなければなりません。このオブジェクトはIDEテンプレートの読み込み時に指示されるので、サブウィンドウ内の任意の場所に置くことができます。これを修正しないと、IDEが正しい位置に表示されなくなるため、。Xの値を保存しておき、後でオブジェクトを正しい場所に表示するために使用します。IDEを正しくレンダリングする関数は以下の通りです。
オブジェクトで使用される基本的な情報はすでに定義されていますが、その他の情報を追加する必要がある場合は、コマンドのセットに追加して、プロパティを適切な値に変更するだけです。
void Resize(int x) { for (int c0 = 0; c0 < m_CountObject; c0++) ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[c0].szName, OBJPROP_XDISTANCE, x + m_ArrObject[c0].iPosX); };
メッセージがどのように処理されるかを見る前に、同様に重要な他の2つの機能を分析しましょう。初期化時に受信したEAから値を受信することができます。これらの値は、Chart Tradeを使用する際に、EAを呼び出すことなく、成行注文または指値注文を送信するように直接設定できるように、正しく表現され調整されている必要があります。両関数は以下の通りです。
void UpdateInfos(bool bSwap = false) { int nContract, FinanceTake, FinanceStop; nContract = (int) StringToInteger(ObjectGetString(Terminal.Get_ID(), m_ArrObject[eEDIT_LEVERAGE].szName, OBJPROP_TEXT)); FinanceTake = (int) StringToInteger(ObjectGetString(Terminal.Get_ID(), m_ArrObject[eEDIT_TAKE].szName, OBJPROP_TEXT)); FinanceStop = (int) StringToInteger(ObjectGetString(Terminal.Get_ID(), m_ArrObject[eEDIT_STOP].szName, OBJPROP_TEXT)); m_IsDayTrade = (bSwap ? (m_IsDayTrade ? false : true) : m_IsDayTrade); ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eCHECK_DAYTRADE].szName, OBJPROP_STATE, m_IsDayTrade); NanoEA.Initilize(nContract, FinanceTake, FinanceStop, clrNONE, clrNONE, clrNONE, m_IsDayTrade); } //+------------------------------------------------------------------+ void InitilizeChartTrade(int nContracts, int FinanceTake, int FinanceStop, color cp, color ct, color cs, bool b1) { NanoEA.Initilize(nContracts, FinanceTake, FinanceStop, cp, ct, cs, b1); if (m_CountObject < eEDIT_STOP) return; ObjectSetString(Terminal.Get_ID(), m_ArrObject[eEDIT_LEVERAGE].szName, OBJPROP_TEXT, IntegerToString(nContracts)); ObjectSetString(Terminal.Get_ID(), m_ArrObject[eEDIT_TAKE].szName, OBJPROP_TEXT, IntegerToString(FinanceTake)); ObjectSetString(Terminal.Get_ID(), m_ArrObject[eEDIT_STOP].szName, OBJPROP_TEXT, IntegerToString(FinanceStop)); ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eCHECK_DAYTRADE].szName, OBJPROP_STATE, m_IsDayTrade = b1); }
なお、IDEは受注システムと連動しているため、システムでおこなった変更は受注システムにも反映されます。こうすることで、以前のようにEA内のデータを変更する必要がなくなります。IDEまたはChart Tradeで直接これをおこなうことができます。これは、メッセージシステムに関連する上記の2つの関数でおこなわれます。
void DispatchMessage(int iMsg, string szArg, double dValue = 0.0) { if (m_CountObject < eEDIT_STOP) return; switch (iMsg) { case CHARTEVENT_CHART_CHANGE: if (szArg == szMsgIDE[eRESULT]) { ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eRESULT].szName, OBJPROP_BGCOLOR, (dValue < 0 ? clrLightCoral : clrLightGreen)); ObjectSetString(Terminal.Get_ID(), m_ArrObject[eRESULT].szName, OBJPROP_TEXT, DoubleToString(dValue, 2)); } break; case CHARTEVENT_OBJECT_CLICK: if (StringSubstr(szArg, 0, StringLen(def_HeaderMSG)) != def_HeaderMSG) return; szArg = StringSubstr(szArg, 9, StringLen(szArg)); StringToUpper(szArg); if ((szArg == szMsgIDE[eBTN_SELL]) || (szArg == szMsgIDE[eBTN_BUY])) NanoEA.OrderMarket(szArg == szMsgIDE[eBTN_BUY]); if (szArg == szMsgIDE[eBTN_CANCEL]) { NanoEA.ClosePosition(); ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eBTN_CANCEL].szName, OBJPROP_STATE, false); } if (szArg == szMsgIDE[eCHECK_DAYTRADE]) UpdateInfos(true); break; case CHARTEVENT_OBJECT_ENDEDIT: UpdateInfos(); break; } }
そして、疑問が生じます。「それだけですか?」はい。これが、MetaTrader 5プラットフォームがIDEと対話できるようにするためのメッセージシステムです。非常にシンプルであることは認めざるを得ませんが、この機能がなければIDEは機能しませんし、システムを構築することもできません。これをEAで実現するのは少し複雑に見えるかもしれませんが、実はOOPのおかげでEAのコードは非常にシンプルなままです。少し厄介なのは、IDEに表示される結果を更新することです。値の更新はOnTick関数でおこないますが、簡単にするために MetaTrader 5 で提供されているデータを使用したので、関数は以下のようになります。この部分は最も重要で、この機能はすべての中で最も要求が多いので、最も速いものであるべきです。
void OnTick() { SubWin.DispatchMessage(CHARTEVENT_CHART_CHANGE, C_Chart_IDE::szMsgIDE[C_Chart_IDE::eRESULT], NanoEA.CheckPosition()); }
つまり、新しい相場が出るたびに、クラスにメッセージが送られ、その結果の値が演算で更新されるのです。しかし、この機能がうまく最適化されないと、深刻な問題が発生することを忘れないでください。
結論
時には不可能と思えることもありますが、私は挑戦が好きです。そして、もともとそのために開発されたわけではないプラットフォームの中で、RADシステムを作る方法を示したこの作品は、なかなか興味深いものでした。簡単なことから始めたこのシステムが、あえて人がやらないような新しいことに挑戦する動機付けになればと思います。
近々、このEAに新しいものを追加する予定ですので、ご期待ください。
MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/10277
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索