【MQL4入門】チャートオブジェクト関数を完全攻略!ObjectCreate・ObjectDelete・ObjectSetの使い方

【初級編】MQLプログラミング基礎

MQL4でEAやインジケーターを開発していると、「チャート上に水平線を引きたい」「テキストラベルで情報を表示したい」という場面が必ず出てきます。こうしたチャート上の描画を担うのがチャートオブジェクト関数です。

この記事では、ObjectCreateObjectDeleteObjectSetIntegerObjectSetDoubleObjectSetStringといった主要関数の使い方を、実践的なコードサンプルとともに徹底解説します。最後には情報パネルを表示するインジケーターの完全コードも用意していますので、ぜひ最後までお読みください。

チャートオブジェクト関数とは?

チャートオブジェクト関数とは、MetaTrader 4のチャート上にライン・図形・テキストなどの「オブジェクト」をプログラムから作成・変更・削除するための関数群です。

手動でチャートに水平線やトレンドラインを描くのと同じことを、MQL4のコードから自動的に行えるようになります。EAでエントリーポイントにマークを付けたり、インジケーターで情報パネルを表示したりと、用途は非常に幅広いです。

ObjectCreate — オブジェクトを作成する

ObjectCreate関数は、チャート上に新しいオブジェクトを作成するための関数です。基本的な書式は以下のとおりです。

bool ObjectCreate(
    string name,       // オブジェクト名(一意な名前を付ける)
    int    type,       // オブジェクトの種類(ENUM_OBJECT)
    int    sub_window, // サブウィンドウ番号(0=メインチャート)
    datetime time1,    // 第1アンカーポイントの時刻
    double   price1,   // 第1アンカーポイントの価格
    ...                // 必要に応じて第2、第3アンカーポイント
);

主なオブジェクト種類(ENUM_OBJECT)一覧

定数名 説明 アンカーポイント数
OBJ_HLINE 水平線 1(価格のみ)
OBJ_VLINE 垂直線 1(時刻のみ)
OBJ_TREND トレンドライン 2
OBJ_RECTANGLE 四角形 2
OBJ_LABEL テキストラベル(座標指定) 0(ピクセル座標)
OBJ_TEXT テキスト(チャート上) 1
OBJ_ARROW 矢印マーク 1
OBJ_RECTANGLE_LABEL 四角形ラベル(背景パネル用) 0(ピクセル座標)

水平線を作成するサンプル

最もシンプルな例として、現在の価格に水平線を引いてみましょう。

void CreateHLine()
{
    string name = "MyHLine";
    double price = Ask;

    // 既に同名のオブジェクトがあれば削除
    if(ObjectFind(name) >= 0)
        ObjectDelete(name);

    // 水平線を作成
    ObjectCreate(name, OBJ_HLINE, 0, 0, price);

    // 色を赤に設定
    ObjectSetInteger(0, name, OBJPROP_COLOR, clrRed);

    // チャートを再描画して反映
    ChartRedraw();
}

ObjectCreateは成功するとtrue、失敗するとfalseを返します。同じ名前のオブジェクトが既に存在する場合は失敗するため、事前にObjectFindで確認するか、先に削除しておくのがポイントです。

ObjectDelete — オブジェクトを削除する

ObjectDelete関数でチャート上のオブジェクトを削除できます。

// 名前を指定して削除
bool ObjectDelete(string name);

// チャートIDを指定して削除(MQL4でも使用可能)
bool ObjectDelete(long chart_id, string name);

使用例:オブジェクトの削除

void RemoveMyObjects()
{
    ObjectDelete("MyHLine");
    ObjectDelete("MyLabel");
    ChartRedraw();
}

⚠️ OnDeinitでの注意点

ObjectDelete関数は非同期で実行されます。つまり、関数を呼び出した瞬間に削除が完了するとは限りません。特にOnDeinit関数内で呼び出す場合、処理が即座に反映されないことがあります。

確実にオブジェクトを削除したい場合は、ObjectsDeleteAll関数を使うか、ObjectDeleteの後にChartRedrawを呼ぶようにしましょう。

void OnDeinit(const int reason)
{
    // プレフィックスが一致するオブジェクトを一括削除
    ObjectsDeleteAll(0, "MyPrefix_");
    ChartRedraw();
}

ObjectsDeleteAllの第2引数にプレフィックス(接頭辞)を指定すると、その文字列で始まる名前のオブジェクトだけを一括削除できます。自作オブジェクトに統一のプレフィックスを付ける習慣を身につけると、管理がとても楽になります。

ObjectSetInteger — 整数プロパティを設定する

ObjectSetInteger関数は、オブジェクトの色・線種・太さなどの整数型プロパティを変更します。

よく使うプロパティ一覧

プロパティ定数 説明 設定値の例
OBJPROP_COLOR オブジェクトの色 clrRed, clrBlue
OBJPROP_STYLE 線のスタイル STYLE_SOLID, STYLE_DASH, STYLE_DOT
OBJPROP_WIDTH 線の太さ 1, 2, 3…
OBJPROP_SELECTABLE ユーザーが選択可能か true / false
OBJPROP_HIDDEN オブジェクトリストに非表示 true / false
OBJPROP_XDISTANCE X座標(ピクセル) 10, 20…
OBJPROP_YDISTANCE Y座標(ピクセル) 10, 20…
OBJPROP_CORNER 基準コーナー CORNER_LEFT_UPPER など

プロパティ設定のサンプル

void StyleHLine(string name)
{
    // 色を青に変更
    ObjectSetInteger(0, name, OBJPROP_COLOR, clrDodgerBlue);

    // 破線スタイルに変更
    ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASH);

    // 線の太さを2に変更
    ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);

    // ユーザーが選択できないようにする
    ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);

    // オブジェクトリストに表示しない
    ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);

    ChartRedraw();
}

OBJPROP_SELECTABLEOBJPROP_HIDDENを設定しておくと、ユーザーが誤ってオブジェクトを移動・削除してしまうのを防げます。EA・インジケーターで自動生成するオブジェクトには、これらを設定しておくのがおすすめです。

ObjectSetDouble / ObjectGetDouble — 実数プロパティの設定と取得

ObjectSetDoubleで価格などのdouble型プロパティを設定し、ObjectGetDoubleで取得できます。

// 水平線の価格を変更する
void MoveHLine(string name, double newPrice)
{
    ObjectSetDouble(0, name, OBJPROP_PRICE, newPrice);
    ChartRedraw();
}

// 水平線の現在の価格を取得する
double GetHLinePrice(string name)
{
    return ObjectGetDouble(0, name, OBJPROP_PRICE);
}

例えば、ユーザーが手動でドラッグした水平線の位置をObjectGetDoubleで読み取り、EAのストップロスやテイクプロフィットに利用するといった活用ができます。

void OnTick()
{
    // ユーザーが配置した "SL_Line" の価格を取得
    if(ObjectFind("SL_Line") >= 0)
    {
        double slPrice = ObjectGetDouble(0, "SL_Line", OBJPROP_PRICE);
        Print("ストップロス価格: ", slPrice);
    }
}

ObjectSetString — 文字列プロパティを設定する

ObjectSetStringは、テキスト内容やフォント名などの文字列型プロパティを変更します。OBJ_LABELOBJ_TEXTオブジェクトで特によく使います。

void CreateTextLabel(string name, string text, int x, int y)
{
    if(ObjectFind(name) >= 0)
        ObjectDelete(name);

    // ラベルオブジェクトを作成
    ObjectCreate(name, OBJ_LABEL, 0, 0, 0);

    // 表示位置を設定(ピクセル座標)
    ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
    ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
    ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);

    // テキスト内容を設定
    ObjectSetString(0, name, OBJPROP_TEXT, text);

    // フォントを設定
    ObjectSetString(0, name, OBJPROP_FONT, "Arial Bold");

    // フォントサイズと色
    ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 12);
    ObjectSetInteger(0, name, OBJPROP_COLOR, clrWhite);

    // 選択不可・リスト非表示
    ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);

    ChartRedraw();
}

OBJ_LABELはチャートの価格・時刻座標ではなく、ピクセル座標で位置を指定するオブジェクトです。OBJPROP_CORNERでどの角を基準にするかを決め、OBJPROP_XDISTANCEOBJPROP_YDISTANCEでその角からの距離を指定します。チャートをスクロールしても位置が固定されるため、情報表示パネルに最適です。

実践サンプル:情報パネルを表示するインジケーター

ここまで学んだ関数を組み合わせて、チャート左上に通貨ペア情報・スプレッド・サーバー時刻を表示する情報パネルインジケーターを作ってみましょう。

//+------------------------------------------------------------------+
//| InfoPanel.mq4 - 情報パネル表示インジケーター                      |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property strict

// オブジェクト名のプレフィックス
#define PREFIX "InfoPanel_"

//+------------------------------------------------------------------+
//| ラベル作成ヘルパー関数                                            |
//+------------------------------------------------------------------+
void CreateLabel(string name, int x, int y, string text,
                 color clr=clrWhite, int fontSize=11)
{
    string fullName = PREFIX + name;

    if(ObjectFind(fullName) < 0)
        ObjectCreate(fullName, OBJ_LABEL, 0, 0, 0);

    ObjectSetInteger(0, fullName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
    ObjectSetInteger(0, fullName, OBJPROP_XDISTANCE, x);
    ObjectSetInteger(0, fullName, OBJPROP_YDISTANCE, y);
    ObjectSetString(0, fullName, OBJPROP_TEXT, text);
    ObjectSetString(0, fullName, OBJPROP_FONT, "Consolas");
    ObjectSetInteger(0, fullName, OBJPROP_FONTSIZE, fontSize);
    ObjectSetInteger(0, fullName, OBJPROP_COLOR, clr);
    ObjectSetInteger(0, fullName, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, fullName, OBJPROP_HIDDEN, true);
}

//+------------------------------------------------------------------+
//| 背景パネル作成関数                                                |
//+------------------------------------------------------------------+
void CreateBackground()
{
    string name = PREFIX + "BG";

    if(ObjectFind(name) < 0)
        ObjectCreate(name, OBJ_RECTANGLE_LABEL, 0, 0, 0);

    ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
    ObjectSetInteger(0, name, OBJPROP_XDISTANCE, 10);
    ObjectSetInteger(0, name, OBJPROP_YDISTANCE, 20);
    ObjectSetInteger(0, name, OBJPROP_XSIZE, 260);
    ObjectSetInteger(0, name, OBJPROP_YSIZE, 100);
    ObjectSetInteger(0, name, OBJPROP_BGCOLOR, C'30,30,50');
    ObjectSetInteger(0, name, OBJPROP_BORDER_TYPE, BORDER_FLAT);
    ObjectSetInteger(0, name, OBJPROP_COLOR, clrDodgerBlue);
    ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
    ObjectSetInteger(0, name, OBJPROP_BACK, false);
    ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
    ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}

//+------------------------------------------------------------------+
//| 初期化                                                            |
//+------------------------------------------------------------------+
int OnInit()
{
    CreateBackground();
    return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| メイン処理                                                        |
//+------------------------------------------------------------------+
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 tfStr = "";
    switch(Period())
    {
        case PERIOD_M1:  tfStr = "M1";  break;
        case PERIOD_M5:  tfStr = "M5";  break;
        case PERIOD_M15: tfStr = "M15"; break;
        case PERIOD_M30: tfStr = "M30"; break;
        case PERIOD_H1:  tfStr = "H1";  break;
        case PERIOD_H4:  tfStr = "H4";  break;
        case PERIOD_D1:  tfStr = "D1";  break;
        case PERIOD_W1:  tfStr = "W1";  break;
        case PERIOD_MN1: tfStr = "MN";  break;
        default:         tfStr = "??";  break;
    }
    CreateLabel("Symbol", 20, 28,
                Symbol() + " / " + tfStr,
                clrDodgerBlue, 13);

    // スプレッド
    double spreadPips = MarketInfo(Symbol(), MODE_SPREAD) / 10.0;
    color spreadClr = (spreadPips < 2.0) ? clrLimeGreen : clrOrangeRed;
    CreateLabel("Spread", 20, 52,
                "Spread: " + DoubleToString(spreadPips, 1) + " pips",
                spreadClr, 11);

    // サーバー時刻
    CreateLabel("Time", 20, 75,
                "Server: " + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS),
                clrSilver, 10);

    ChartRedraw();
    return(rates_total);
}

//+------------------------------------------------------------------+
//| 終了処理                                                          |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
    ObjectsDeleteAll(0, PREFIX);
    ChartRedraw();
}

このインジケーターをチャートに適用すると、左上にダークブルーの背景パネルが表示され、通貨ペア・時間足・スプレッド・サーバー時刻がリアルタイムで更新されます。スプレッドが2.0pips未満なら緑色、それ以上ならオレンジ色で表示される仕組みです。

よくあるミスと対策

1. オブジェクト名の重複

ObjectCreateは、既に同名のオブジェクトが存在するとfalseを返して失敗します。オブジェクトを更新したい場合は、先にObjectFindで存在チェックをするか、ObjectDeleteで削除してから再作成しましょう。

上記の実践サンプルのように、既に存在する場合はObjectCreateをスキップしてプロパティだけ更新するパターンも効率的です。

2. ChartRedraw()の呼び忘れ

オブジェクトの作成や変更後にChartRedraw()を呼ばないと、画面に変更が反映されません。特にOnCalculateOnTickの中でオブジェクトを操作した場合、最後に必ずChartRedraw()を呼ぶ習慣をつけましょう。

// NG: 表示が更新されないことがある
ObjectSetString(0, "label1", OBJPROP_TEXT, "新しいテキスト");

// OK: 確実に画面に反映される
ObjectSetString(0, "label1", OBJPROP_TEXT, "新しいテキスト");
ChartRedraw();

3. OnDeinitでの削除漏れ

インジケーターやEAを削除したとき、作成したオブジェクトがチャートに残ってしまうのはよくあるミスです。OnDeinit関数内で必ずオブジェクトを削除しましょう。

おすすめは、すべてのオブジェクト名に共通のプレフィックスを付けて、ObjectsDeleteAll(0, PREFIX)で一括削除する方法です。この方法なら、オブジェクトを追加した際に削除コードの更新を忘れる心配がありません。

まとめ

今回はMQL4のチャートオブジェクト関数について解説しました。ポイントを整理します。

  • ObjectCreateでオブジェクトを作成。同名オブジェクトの存在チェックを忘れずに
  • ObjectDelete / ObjectsDeleteAllで削除。プレフィックスを活用した一括削除が便利
  • ObjectSetIntegerで色・線種・太さ・座標などを設定
  • ObjectSetDouble / ObjectGetDoubleで価格値の設定・取得
  • ObjectSetStringでテキスト内容やフォントを変更
  • 操作後はChartRedraw()で画面を再描画
  • OnDeinitでは必ずオブジェクトを削除して後片付け

チャートオブジェクト関数を使いこなせるようになると、EAやインジケーターの視覚的な表現力が大幅にアップします。まずは水平線やテキストラベルなど、シンプルなオブジェクトから試してみてください。慣れてきたら、今回の情報パネルサンプルをベースに、自分だけのカスタムパネルを作ってみましょう!