FX自動売買基礎と応用

Comment関数を拡張する方法【MQLプログラミングの基礎】


1.ファイルを新規作成して接頭辞を定義


この記事では、Comment関数を拡張する方法について解説します。Comment関数はMT4に標準搭載されている関数で、指定した文字列をチャートの左上に小さく表示できます。

しかし、文字サイズやフォントの種類を変えることができません。そこで今回は、文字サイズ等をパラメーターで指定できるように、文字列表示用の関数を作ります。

まずはファイルの新規作成で「カスタムインディケータ」を選択し、ファイル名を「CommentEx」とします。「カスタムインディケータのイベントハンドラ」の画面では、「OnTimer」と「OnChartEvent」のどちらにもチェックを入れず次へ進み、「完了」をクリックすれば、ひな形の完成です。

「カスタムインディケータのイベントハンドラ」の画面

今回はオブジェクトを使うので、ファイル上部のプロパティ「#property indicator_chart_window」の下で接頭辞「PREFIX」を定義しましょう。これを定義しておくと、オブジェクトをまとめて扱えるようになります。

「MQLInfoString(MQL_PROGRAM_NAME)」はインジケーターのファイル名を示します。


#define PREFIX MQLInfoString(MQL_PROGRAM_NAME) + "_"

そして、「Custom indicator initialization function」の下に「Custom indicator deinitialization function」を設けて、OnDeinit関数を使った次のコードを記述します。これでインジケーターをチャートから削除したときに関連オブジェクトやコメントが一緒に消えるようになります。


void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0, PREFIX);
   Comment("");
}


2.Comment関数で文字列を出力


最初に、通常のComment関数を利用して文字列を表示する例を示します。stringで「text」という文字列を定義し、それをComment関数の括弧内に指定して表示してみましょう。


string text = "123\n345\nabc\ndef\nあいうえお\nかきくけこ";
Comment(text);

これでコンパイルしてチャートにセットすると、チャートの左上に改行の入った文字列が表示されます。通常のComment関数で表示される文字列は小さく、やや見にくいのが難点です。

Comment関数で文字列を出力


3.文字列表示用の関数を作成


上記では、通常のComment関数を使って、チャートに文字列を表示するところまで説明しました。続いて、その文字列の配置位置やサイズ、色などを指定できるようにカスタマイズします。

ファイルの「Custom indicator iteration function」の下に「Comment function」を設けて、そこに文字列表示用の関数を新たに作りましょう。今回は文字、フォント、位置、行間の幅、サイズ、色を指定して処理できるようにします。まずは、文字列を受け取ったときに、改行ごとに文字を判定して配列に格納したいので、そのための配列を定義します。


void CommentEx(string text, string font, int x, int y, int gap, int size, color clr)
{
   string comment[];
}

次に、while文を用いて繰り返し処理を行います。while文はfor文と異なり、括弧の中の条件が成立している間は繰り返し処理が継続される仕組みです。ここでは括弧の中に「true」を入れて無限ループとし、if文の条件が成立したときに「break」で強制的にその無限ループを抜ける使い方をします。

「pos」と「pre」を定義し、文字列の中から改行の位置を探してposに入れます。posが-1ではなかったとき(改行が見つかったとき)は、前回の場所から改行の位置までの文字列を切り取ってcomment配列に格納します。そして、改行を見つけた次の場所から検索を開始したいので、次の場所をpreに代入しておきます。comment配列は、最初はサイズがない状態なので、「ArrayResize」を使ってサイズを少しずつ大きくしていきましょう。


int pos = 0, pre = 0;
while (true) {
   int n = ArraySize(comment);
   ArrayResize(comment, n + 1);  
   pos = StringFind(text, "\n", pre);
   if (pos != -1) {
      comment[n] = StringSubstr(text, pre, pos - pre);
      pre = pos + 1;
}

なお、posが-1だったとき(改行が見つからなかったとき)は、そこでループ処理を終了します。


} else {
   comment[n] = StringSubstr(text, pre);
   break;
}


4.Labelオブジェクトのサンプルコードをコピー


今回はLabelオブジェクトを利用して文字列を表示するので、LabelオブジェクトのサンプルコードをMQL4リファレンスからコピーします。MQL4リファレンスの目次にある「Constants, Enumerations and Structures」→「Objects Constants」→「Object Types」をクリックするとオブジェクトの一覧が表示されるので、その中から「OBJ_LABEL」を選択し、あらかじめ用意されている「Create a text label」のコードをコピーしてファイル下部に貼り付けましょう。


//+------------------------------------------------------------------+
//| Create a text label                                              |
//+------------------------------------------------------------------+
bool LabelCreate(const long              chart_ID = 0,             // chart's ID
                 const string            name = "Label",           // label name
                 const int               sub_window = 0,           // subwindow index
                 const int               x = 0,                    // X coordinate
                 const int               y = 0,                    // Y coordinate
                 const ENUM_BASE_CORNER  corner = CORNER_LEFT_UPPER, // chart corner for anchoring
                 const string            text = "Label",           // text
                 const string            font = "Arial",           // font
                 const int               font_size = 10,           // font size
                 const color             clr = clrRed,             // color
                 const double            angle = 0.0,              // text slope
                 const ENUM_ANCHOR_POINT anchor = ANCHOR_LEFT_UPPER, // anchor type
                 const bool              back = false,             // in the background
                 const bool              selection = false,        // highlight to move
                 const bool              hidden = true,            // hidden in the object list
                 const long              z_order = 0)              // priority for mouse click
{
//--- reset the error value
   ResetLastError();
//--- create a text label
   if(!ObjectCreate(chart_ID, name, OBJ_LABEL, sub_window, 0, 0)) {
      Print(__FUNCTION__,
            ": failed to create text label! Error code = ", GetLastError());
      return(false);
   }
//--- set label coordinates
   ObjectSetInteger(chart_ID, name, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(chart_ID, name, OBJPROP_YDISTANCE, y);
//--- set the chart's corner, relative to which point coordinates are defined
   ObjectSetInteger(chart_ID, name, OBJPROP_CORNER, corner);
//--- set the text
   ObjectSetString(chart_ID, name, OBJPROP_TEXT, text);
//--- set text font
   ObjectSetString(chart_ID, name, OBJPROP_FONT, font);
//--- set font size
   ObjectSetInteger(chart_ID, name, OBJPROP_FONTSIZE, font_size);
//--- set the slope angle of the text
   ObjectSetDouble(chart_ID, name, OBJPROP_ANGLE, angle);
//--- set anchor type
   ObjectSetInteger(chart_ID, name, OBJPROP_ANCHOR, anchor);
//--- set color
   ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(chart_ID, name, OBJPROP_BACK, back);
//--- enable (true) or disable (false) the mode of moving the label by mouse
   ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, selection);
   ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, selection);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(chart_ID, name, OBJPROP_HIDDEN, hidden);
//--- set the priority for receiving the event of a mouse click in the chart
   ObjectSetInteger(chart_ID, name, OBJPROP_ZORDER, z_order);
//--- successful execution
   return(true);
}


5.LabelCreateで文字列を表示


上記では、文字列表示用の関数を作成し、Labelオブジェクトのサンプルコードをコピーして使えるようにしました。続いて、comment配列に格納した文字列を、LabelCreateで順番に表示していきます。

チャートIDは「0」、名前は「PREFIX + “Text” + (string)i」、ウィンドウはメインウィンドウなので「0」、場所はX座標が「x」、Y座標が「y + i * gap」、コーナーは左上にしたいので「CORNER_LEFT_UPPER」、表示するテキストは格納した文字列「comment[i]」、フォントは「font」、サイズは「size」、色は「clr」、アングルは「0」、アンカーは「ANCHOR_LEFT_UPPER」とします。


for (int i = 0; i < ArraySize(comment); i++) {
   LabelCreate(0, PREFIX + "Text" + (string)i, 0, x, y + i * gap, CORNER_LEFT_UPPER, comment[i], font, size, clr, 0, ANCHOR_LEFT_UPPER); 
}

そして「Comment(text)」の代わりに、作った関数「CommentEx」を実行するようにします。OnCalculate関数内のComment(text)の頭に「//」をつけてコメント扱いとし、その下に次のコードを加えます。フォントは「メイリオ」、色は「clrAqua」にします。


CommentEx(text, "メイリオ", 0, 15, 25, 14, clrAqua);

これでコンパイルすると、チャート左上に文字列が大きく水色で表示されることが分かります。このように文字列表示用の関数を作ることで、Comment関数ではできなかった文字サイズ等のパラメーター指定が可能となります。

チャート左上に文字列が大きく水色で表示される


6.ソースコード


今回、作成したソースコードは下記の通りです。


//+------------------------------------------------------------------+
//|                                                    CommentEx.mq4 |
//|                        Copyright 2022, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
#property indicator_chart_window
#define PREFIX MQLInfoString(MQL_PROGRAM_NAME) + "_"
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                         |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0, PREFIX);
   Comment("");
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
//---
   string text = "123\n345\nabc\ndef\nあいうえお\nかきくけこ";
//   Comment(text);
   CommentEx(text, "メイリオ", 0, 15, 25, 14, clrAqua);

//--- return value of prev_calculated for next call
   return(rates_total);
}
//+------------------------------------------------------------------+
//| Comment function                                                 |
//+------------------------------------------------------------------+
void CommentEx(string text, string font, int x, int y, int gap, int size, color clr)
{
   string comment[];
   int pos = 0, pre = 0;
   while (true) {
      int n = ArraySize(comment);
      ArrayResize(comment, n + 1);
      pos = StringFind(text, "\n", pre);
      if (pos != -1) {
         comment[n] = StringSubstr(text, pre, pos - pre);
         pre = pos + 1;
      } else {
         comment[n] = StringSubstr(text, pre);
         break;
      }
   }

   for (int i = 0; i < ArraySize(comment); i++) {
      LabelCreate(0, PREFIX + "Text" + (string)i, 0, x, y + i * gap, CORNER_LEFT_UPPER, comment[i], font, size, clr, 0, ANCHOR_LEFT_UPPER);
   }
}
//+------------------------------------------------------------------+
//| Create a text label                                              |
//+------------------------------------------------------------------+
bool LabelCreate(const long              chart_ID = 0,             // chart's ID
                 const string            name = "Label",           // label name
                 const int               sub_window = 0,           // subwindow index
                 const int               x = 0,                    // X coordinate
                 const int               y = 0,                    // Y coordinate
                 const ENUM_BASE_CORNER  corner = CORNER_LEFT_UPPER, // chart corner for anchoring
                 const string            text = "Label",           // text
                 const string            font = "Arial",           // font
                 const int               font_size = 10,           // font size
                 const color             clr = clrRed,             // color
                 const double            angle = 0.0,              // text slope
                 const ENUM_ANCHOR_POINT anchor = ANCHOR_LEFT_UPPER, // anchor type
                 const bool              back = false,             // in the background
                 const bool              selection = false,        // highlight to move
                 const bool              hidden = true,            // hidden in the object list
                 const long              z_order = 0)              // priority for mouse click
{
//--- reset the error value
   ResetLastError();
//--- create a text label
   if(!ObjectCreate(chart_ID, name, OBJ_LABEL, sub_window, 0, 0)) {
      Print(__FUNCTION__,
            ": failed to create text label! Error code = ", GetLastError());
      return(false);
   }
//--- set label coordinates
   ObjectSetInteger(chart_ID, name, OBJPROP_XDISTANCE, x);
   ObjectSetInteger(chart_ID, name, OBJPROP_YDISTANCE, y);
//--- set the chart's corner, relative to which point coordinates are defined
   ObjectSetInteger(chart_ID, name, OBJPROP_CORNER, corner);
//--- set the text
   ObjectSetString(chart_ID, name, OBJPROP_TEXT, text);
//--- set text font
   ObjectSetString(chart_ID, name, OBJPROP_FONT, font);
//--- set font size
   ObjectSetInteger(chart_ID, name, OBJPROP_FONTSIZE, font_size);
//--- set the slope angle of the text
   ObjectSetDouble(chart_ID, name, OBJPROP_ANGLE, angle);
//--- set anchor type
   ObjectSetInteger(chart_ID, name, OBJPROP_ANCHOR, anchor);
//--- set color
   ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(chart_ID, name, OBJPROP_BACK, back);
//--- enable (true) or disable (false) the mode of moving the label by mouse
   ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, selection);
   ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, selection);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(chart_ID, name, OBJPROP_HIDDEN, hidden);
//--- set the priority for receiving the event of a mouse click in the chart
   ObjectSetInteger(chart_ID, name, OBJPROP_ZORDER, z_order);
//--- successful execution
   return(true);
}


本記事の監修者・HT FX


2013年にFXを開始し、その後専業トレーダーへ。2014年からMT4/MT5のカスタムインジケーターの開発に取り組む。ブログでは100本を超えるインジケーターを無料公開。投資スタイルは自作の秒足インジケーターを利用したスキャルピング。

EA(自動売買)を学びたい方へオススメコンテンツ

EA運用の注意点

OANDAではEA(自動売買)を稼働するプラットフォームMT4/MT5の基本的な使い方について、画像や動画付きで詳しく解説しています。MT4/MT5のインストールからEAの設定方法までを詳しく解説しているので、初心者の方でもスムーズにEA運用を始めることが可能です。またOANDAの口座をお持ちであれば、独自開発したオリジナルインジケーターを無料で利用することもできます。EA運用をお考えであれば、ぜひ口座開設をご検討ください。


本ホームページに掲載されている事項は、投資判断の参考となる情報の提供を目的としたものであり、投資の勧誘を目的としたものではありません。投資方針、投資タイミング等は、ご自身の責任において判断してください。本サービスの情報に基づいて行った取引のいかなる損失についても、当社は一切の責を負いかねますのでご了承ください。また、当社は、当該情報の正確性および完全性を保証または約束するものでなく、今後、予告なしに内容を変更または廃止する場合があります。なお、当該情報の欠落・誤謬等につきましてもその責を負いかねますのでご了承ください。

この記事をシェアする

ホーム » FX自動売買基礎と応用 » Comment関数を拡張する方法【MQLプログラミングの基礎】