MT5で複数チャートでのクロスヘアライン同期ツールを作成する【MQLプログラミングの基礎】
1.ファイルの新規作成
この記事では、自チャートへ表示させたクロスヘアライン(水平線と垂直線)と同じものを、他のチャートへ同期表示するツールを作成します。
※この記事はMQL5の内容です。MQL4に対応した類似記事は以下を参照してください。
MetaEditorの「新規作成」アイコンをクリックしてMQLウィザードを開始します。

「カスタムインディケータ」を選択して「次へ」をクリック。

ファイル名を「Crosshair_Sync.mq5」とし、「次へ」をクリック。

イベントハンドラは一番上のOnCalculate(…,open,high,low,close)とOnChartEventを選択して「次へ」をクリック。

「カスタムインディケータの描画プロパティ」では、特に何も追加せず「完了」をクリックすれば、ファイルのベースが作成されます。
今回のファイルでは、インジケーターバッファを利用しないので、「#property indicator_chart_window」の行の下へ、下記を追記します。
#property indicator_buffers 0
#property indicator_plots 0
2.キーボードで表示切り替え操作
キーボードのキー押下操作で、クロスヘアラインの表示切り替えをするため、変数を定義します。
「#property indicator_plots 0」の下へ、下記を追記します。
bool show;
OnInit関数内に下記を追記し、変数showの初期値をfalseに設定します(trueは表示、falseは非表示として扱います)。
show = false;
キーボードで表示切り替え操作をするために、キーの番号を確認します。
OnChartEvent関数内に下記を追記してキーを押すと、そのキーの番号がツールボックスのエキスパートタブに表示されます(ツールボックスは、MT5メニューの「表示」で表示切り替えできます)。
if (id == CHARTEVENT_KEYDOWN) {
Print(sparam);
}
今回は、「Xキー」を利用します。
「Xキー」を押すと該当する番号は「45」であることを確認できます。

「Xキー」操作で、表示/非表示の切り替え操作をするために、OnChartEvent関数内に追加したif文の「Print(sparam);」を削除し、下記のように変更します。
if (id == CHARTEVENT_KEYDOWN) {
if ((int)sparam == 45) {
show = !show;
}
}
「Xキー」を押す度に、showの値がfalseからtrue、trueからfalseへ交互に切り替えられます。
3.自チャートへのクロスヘアライン表示
クロスヘアラインをリアルタイムでカーソルの位置へ表示するために、OnInit関数内へ下記を追記します。
ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
変数showがtureのとき、マウスカーソルの位置(XY座標)を取得するため、OnChartEvent関数内に下記を追記します。
if (id == CHARTEVENT_MOUSE_MOVE) {
if (show) {
int x = (int)lparam;
int y = (int)dparam;
}
}
XY座標情報を時間と価格に変換するため、「int y = (int)dparam;」の下へ下記を追記します。
int win = 0;
datetime time = 0;
double price = 0;
if (ChartXYToTimePrice(0, x, y, win, time, price)) {
}
ChartXYToTimePriceでの座標変換が成功すると、変数timeにマウスカーソル位置の時間、priceに価格の値が入力されます。
取得した時間の位置に垂直線、価格の位置に水平線を表示するために、MQLリファレンス内にある関数を利用します。
MetaEditorメニューの「ヘルプ」から「MQL5リファレンス」を開いて、「目次」タブを選択し、「標準的な定数、列挙と構造体」→「オブジェクト定数」→「オブジェクト型」にある「OBJ_VLINE」を選択してください。

OBJ_VLINE内にある「//| 垂直線を作成する」以下にあるVLineCreate関数をコピーして、今回のプログラムの最下部へ貼り付けます。
――――― コピーして貼り付けするコード(ここから) ―――――
//+------------------------------------------------------------------+
//| 垂直線を作成する |
//+------------------------------------------------------------------+
bool VLineCreate(const long chart_ID=0, // チャート識別子
const string name="VLine", // 線の名称
const int sub_window=0, // サブウィンドウ番号
datetime time=0, // 線の時間
const color clr=clrRed, // 線の色
const ENUM_LINE_STYLE style=STYLE_SOLID, // 線のスタイル
const int width=1, // 線の幅
const bool back=false, // 背景で表示する
const bool selection=true, // 強調表示して移動
const bool ray=true, // 線が下に続く
const bool hidden=true, // オブジェクトリストに隠す
const long z_order=0) // マウスクリックの優先順位
{
//--- 線の時間が設定されていない場合、最後のバーで描画する
if(!time)
time=TimeCurrent();
//--- エラー値をリセットする
ResetLastError();
//--- 垂直線を作成する
if(!ObjectCreate(chart_ID,name,OBJ_VLINE,sub_window,time,0))
{
Print(__FUNCTION__,
": failed to create a vertical line! Error code = ",GetLastError());
return(false);
}
//--- 線の色を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- 線の表示スタイルを設定する
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- 線の幅を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- 前景(false)または背景(true)に表示
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- マウスで線を移動させるモードを有効(true)か無効(false)にする
//--- ObjectCreate 関数を使用してグラフィックオブジェクトを作成する際、オブジェクトは
//--- デフォルトではハイライトされたり動かされたり出来ない。このメソッド内では、選択パラメータは
//--- デフォルトでは true でハイライトと移動を可能にする。
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- チャートサブウィンドウで線を表示するモードを有効(true)か無効(false)にする
ObjectSetInteger(chart_ID,name,OBJPROP_RAY,ray);
//--- オブジェクトリストのグラフィックオブジェクトを非表示(true)か表示(false)にする
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- チャートのマウスクリックのイベントを受信するための優先順位を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- 実行成功
return(true);
}
//+------------------------------------------------------------------+
――――― コピーして貼り付けするコード(ここまで) ―――――
同様に「オブジェクト型」にある「OBJ_HLINE」を選択し、「//| 水平線を作成する」以下にあるHLineCreate関数をコピーして、今回のプログラムの最下部へ貼り付けます。
――――― コピーして貼り付けするコード(ここから) ―――――
//+------------------------------------------------------------------+
//| 水平線を作成する |
//+------------------------------------------------------------------+
bool HLineCreate(const long chart_ID=0, // チャート識別子
const string name="HLine", // 線の名称
const int sub_window=0, // サブウィンドウ番号
double price=0, // 線の価格
const color clr=clrRed, // 線の色
const ENUM_LINE_STYLE style=STYLE_SOLID, // 線のスタイル
const int width=1, // 線の幅
const bool back=false, // 背景で表示する
const bool selection=true, // 強調表示して移動
const bool hidden=true, // オブジェクトリストに隠す
const long z_order=0) // マウスクリックの優先順位
{
//--- 価格が設定されていない場合、現在の売値レベルで設定する
if(!price)
price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- エラー値をリセットする
ResetLastError();
//--- 水平線を作成する
if(!ObjectCreate(chart_ID,name,OBJ_HLINE,sub_window,0,price))
{
Print(__FUNCTION__,
": failed to create a horizontal line! Error code = ",GetLastError());
return(false);
}
//--- 線の色を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- 線の表示スタイルを設定する
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- 線の幅を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- 前景(false)または背景(true)に表示
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- マウスで線を移動させるモードを有効(true)か無効(false)にする
//--- ObjectCreate 関数を使用してグラフィックオブジェクトを作成する際、オブジェクトは
//--- デフォルトではハイライトされたり動かされたり出来ない。このメソッド内では、選択パラメータは
//--- デフォルトでは true でハイライトと移動を可能にする。
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- オブジェクトリストのグラフィックオブジェクトを非表示(true)か表示(false)にする
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- チャートのマウスクリックのイベントを受信するための優先順位を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- 実行成功
return(true);
}
//+------------------------------------------------------------------+
――――― コピーして貼り付けするコード(ここまで) ―――――
コピーした関数を利用し、if (ChartXYToTimePrice(0, x, y, win, time, price)) { }のカッコ内へ下記を追記します。
color clrFore = (color)ChartGetInteger(0, CHART_COLOR_FOREGROUND);
VLineCreate(0, "CrosshairVLine", 0, time, clrFore, STYLE_SOLID, 1, false, false);
HLineCreate(0, "CrosshairHLine", 0, price, clrFore, STYLE_SOLID, 1, false, false);
ChartRedraw();
ラインの色は、ChartGetInteger関数を利用してチャートの前景色を取得し指定しています。
変数showがfalseのとき、クロスヘアラインを消去するため、if (id == CHARTEVENT_KEYDOWN) { }のカッコ内の「show = !show;」の下へ下記を追記します。
if (!show) {
ObjectDelete(0, "CrosshairVLine");
ObjectDelete(0, "CrosshairHLine");
ChartRedraw();
}
ここまでの状態でコンパイルし、本インジケーターをチャートにセットして、マウスカーソルがチャート上にある状態で「Xキー」を押すと、マウスカーソルの位置にクロスヘアラインが表示されます。
再度「Xキー」を押すと、クロスヘアラインは消去されます。

コピーしてきたHLineCreate関数のままでは、水平線上にマウスカーソルが乗っていることにより、ツールチップ(オブジェクト名称や価格)が表示されてしまいます。
HLineCreate関数およびVLineCreate関数内の「ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);」の下に、下記を追記します。
ObjectSetString(chart_ID,name,OBJPROP_TOOLTIP,"\n");
上記を追加することで、ツールチップが表示されなくなります。
4.他チャートへのクロスヘアライン同期表示
現在、自チャートにのみ表示しているクロスヘアラインを他チャートにも表示させるため、if (ChartXYToTimePrice(0, x, y, win, time, price)) { }のカッコ内に、下記を追記します。
long chartId = ChartFirst(); // 先頭チャートのID
while (true) {
chartId = ChartNext(chartId); // 次のチャートIDに切替
if (chartId < 0) break; // 全チャート検索で終了
}
変数chartIdに先頭のチャートIDが入力され、ChartNext関数でチャートIDを切り替えながら、全チャートに対して処理が実行されます。
ChartNext関数は、最後のチャートになると、「-1」を返すので、そこで処理終了となります。
全チャートにクロスヘアラインを表示するため、上記のwhile文内に下記を追記します(自チャートに描画していたクロスヘアラインの式は削除します)。
color clrFore = (color)ChartGetInteger(chartId, CHART_COLOR_FOREGROUND);
VLineCreate(chartId, "CrosshairVLine", 0, time, clrFore, STYLE_SOLID, 1, false, false);
HLineCreate(chartId, "CrosshairHLine", 0, price, clrFore, STYLE_SOLID, 1, false, false);
ChartRedraw(chartId);
非表示に切り替えた際、描画した全クロスヘアラインを削除するため、if (!show) { }のカッコ内のクロスヘアライン削除の式を下記へ置き換えます。
if (!show) {
long chartId = ChartFirst(); // 先頭チャートのID
while (true) {
ObjectDelete(chartId, "CrosshairVLine");
ObjectDelete(chartId, "CrosshairHLine");
ChartRedraw(chartId);
chartId = ChartNext(chartId); // 次のチャートIDに切替
if (chartId < 0) break; // 全チャート検索で終了
}
}
上記までの状態でコンパイルを実行し、本ツールをセットしたチャート上にマウスカーソルを乗せた状態で「Xキー」を押すと、全チャートにクロスヘアラインがリアルタイムで同期表示されることを確認できます。

本ツールをチャートから削除したときなどに、各チャートのクロスヘアライン表示が残らないよう、下記をOnInit関数の下などへ追加してください(他の関数の外であれば、位置は任意)。
void OnDeinit(const int reason)
{
long chartId = ChartFirst(); // 先頭チャートのID
while (true) {
ObjectDelete(chartId, "CrosshairVLine");
ObjectDelete(chartId, "CrosshairHLine");
ChartRedraw(chartId);
chartId = ChartNext(chartId); // 次のチャートIDに切替
if (chartId < 0) break; // 全チャート検索で終了
}
}
上記までの作業で、今回のツールは完成です。
5.ソースコード
今回、作成したソースコードは下記の通りです。
//+------------------------------------------------------------------+
//| Crosshair_Sync.mq5 |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots 0
bool show;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
show = false;
ChartSetInteger(0, CHART_EVENT_MOUSE_MOVE, true);
//---
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
long chartId = ChartFirst(); // 先頭チャートのID
while (true) {
ObjectDelete(chartId, "CrosshairVLine");
ObjectDelete(chartId, "CrosshairHLine");
ChartRedraw(chartId);
chartId = ChartNext(chartId); // 次のチャートIDに切替
if (chartId < 0) break; // 全チャート検索で終了
}
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int32_t rates_total,
const int32_t 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 int32_t &spread[])
{
//---
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int32_t id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//---
if (id == CHARTEVENT_KEYDOWN) {
if ((int)sparam == 45) {
show = !show;
if (!show) {
long chartId = ChartFirst(); // 先頭チャートのID
while (true) {
ObjectDelete(chartId, "CrosshairVLine");
ObjectDelete(chartId, "CrosshairHLine");
ChartRedraw(chartId);
chartId = ChartNext(chartId); // 次のチャートIDに切替
if (chartId < 0) break; // 全チャート検索で終了
}
}
}
}
if (id == CHARTEVENT_MOUSE_MOVE) {
if (show) {
int x = (int)lparam;
int y = (int)dparam;
int win = 0;
datetime time = 0;
double price = 0;
if (ChartXYToTimePrice(0, x, y, win, time, price)) {
long chartId = ChartFirst(); // 先頭チャートのID
while (true) {
color clrFore = (color)ChartGetInteger(chartId, CHART_COLOR_FOREGROUND);
VLineCreate(chartId, "CrosshairVLine", 0, time, clrFore, STYLE_SOLID, 1, false, false);
HLineCreate(chartId, "CrosshairHLine", 0, price, clrFore, STYLE_SOLID, 1, false, false);
ChartRedraw(chartId);
chartId = ChartNext(chartId); // 次のチャートIDに切替
if (chartId < 0) break; // 全チャート検索で終了
}
}
}
}
}
//+------------------------------------------------------------------+
//| 垂直線を作成する |
//+------------------------------------------------------------------+
bool VLineCreate(const long chart_ID=0, // チャート識別子
const string name="VLine", // 線の名称
const int sub_window=0, // サブウィンドウ番号
datetime time=0, // 線の時間
const color clr=clrRed, // 線の色
const ENUM_LINE_STYLE style=STYLE_SOLID, // 線のスタイル
const int width=1, // 線の幅
const bool back=false, // 背景で表示する
const bool selection=true, // 強調表示して移動
const bool ray=true, // 線が下に続く
const bool hidden=true, // オブジェクトリストに隠す
const long z_order=0) // マウスクリックの優先順位
{
//--- 線の時間が設定されていない場合、最後のバーで描画する
if(!time)
time=TimeCurrent();
//--- エラー値をリセットする
ResetLastError();
//--- 垂直線を作成する
if(!ObjectCreate(chart_ID,name,OBJ_VLINE,sub_window,time,0))
{
Print(__FUNCTION__,
": failed to create a vertical line! Error code = ",GetLastError());
return(false);
}
//--- 線の色を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- 線の表示スタイルを設定する
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- 線の幅を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- 前景(false)または背景(true)に表示
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- マウスで線を移動させるモードを有効(true)か無効(false)にする
//--- ObjectCreate 関数を使用してグラフィックオブジェクトを作成する際、オブジェクトは
//--- デフォルトではハイライトされたり動かされたり出来ない。このメソッド内では、選択パラメータは
//--- デフォルトでは true でハイライトと移動を可能にする。
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- チャートサブウィンドウで線を表示するモードを有効(true)か無効(false)にする
ObjectSetInteger(chart_ID,name,OBJPROP_RAY,ray);
//--- オブジェクトリストのグラフィックオブジェクトを非表示(true)か表示(false)にする
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- チャートのマウスクリックのイベントを受信するための優先順位を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
ObjectSetString(chart_ID,name,OBJPROP_TOOLTIP,"\n");
//--- 実行成功
return(true);
}
//+------------------------------------------------------------------+
//| 水平線を作成する |
//+------------------------------------------------------------------+
bool HLineCreate(const long chart_ID=0, // チャート識別子
const string name="HLine", // 線の名称
const int sub_window=0, // サブウィンドウ番号
double price=0, // 線の価格
const color clr=clrRed, // 線の色
const ENUM_LINE_STYLE style=STYLE_SOLID, // 線のスタイル
const int width=1, // 線の幅
const bool back=false, // 背景で表示する
const bool selection=true, // 強調表示して移動
const bool hidden=true, // オブジェクトリストに隠す
const long z_order=0) // マウスクリックの優先順位
{
//--- 価格が設定されていない場合、現在の売値レベルで設定する
if(!price)
price=SymbolInfoDouble(Symbol(),SYMBOL_BID);
//--- エラー値をリセットする
ResetLastError();
//--- 水平線を作成する
if(!ObjectCreate(chart_ID,name,OBJ_HLINE,sub_window,0,price))
{
Print(__FUNCTION__,
": failed to create a horizontal line! Error code = ",GetLastError());
return(false);
}
//--- 線の色を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- 線の表示スタイルを設定する
ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
//--- 線の幅を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
//--- 前景(false)または背景(true)に表示
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- マウスで線を移動させるモードを有効(true)か無効(false)にする
//--- ObjectCreate 関数を使用してグラフィックオブジェクトを作成する際、オブジェクトは
//--- デフォルトではハイライトされたり動かされたり出来ない。このメソッド内では、選択パラメータは
//--- デフォルトでは true でハイライトと移動を可能にする。
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- オブジェクトリストのグラフィックオブジェクトを非表示(true)か表示(false)にする
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- チャートのマウスクリックのイベントを受信するための優先順位を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
ObjectSetString(chart_ID,name,OBJPROP_TOOLTIP,"\n");
//--- 実行成功
return(true);
}
//+------------------------------------------------------------------+
本記事の監修者・HT FX
2013年にFXを開始し、その後専業トレーダーへ。2014年からMT4/MT5のカスタムインジケーターの開発に取り組む。ブログでは100本を超えるインジケーターを無料公開。投資スタイルは自作の秒足インジケーターを利用したスキャルピング。
EA(自動売買)を学びたい方へオススメコンテンツ

OANDAではEA(自動売買)を稼働するプラットフォームMT4/MT5の基本的な使い方について、画像や動画付きで詳しく解説しています。MT4/MT5のインストールからEAの設定方法までを詳しく解説しているので、初心者の方でもスムーズにEA運用を始めることが可能です。またOANDAの口座をお持ちであれば、独自開発したオリジナルインジケーターを無料で利用することもできます。EA運用をお考えであれば、ぜひ口座開設をご検討ください。
本ホームページに掲載されている事項は、投資判断の参考となる情報の提供を目的としたものであり、投資の勧誘を目的としたものではありません。投資方針、投資タイミング等は、ご自身の責任において判断してください。本サービスの情報に基づいて行った取引のいかなる損失についても、当社は一切の責を負いかねますのでご了承ください。また、当社は、当該情報の正確性および完全性を保証または約束するものでなく、今後、予告なしに内容を変更または廃止する場合があります。なお、当該情報の欠落・誤謬等につきましてもその責を負いかねますのでご了承ください。