アラート専用の価格ラインを1本引くために、「あと3pips上に線を引きたい」
と思うたびに、コードの数値を書き換えてコンパイルし直していませんか。
ObjectGetDouble・ObjectSetDoubleという関数と、
CHARTEVENT_OBJECT_DRAGというイベントを組み合わせれば、
チャート上でラインをマウスでドラッグするだけで、
アラート価格をその場で変更できるツールが作れます。
この記事では、非推奨になった旧関数ObjectGet/ObjectSetとの違いから、
ドラッグされた価格を取得してアラートを出す設計まで、実際に動くコード付きで解説します。
・ObjectGetDouble/ObjectSetDoubleの基本構文
・非推奨になった旧ObjectGet/ObjectSetとの違い
・マウスでドラッグできる価格ラインの作り方
・CHARTEVENT_OBJECT_DRAGでドラッグ後の新しい価格を取得する方法
・価格到達時に一度だけアラートを鳴らし、ライン移動で再武装する設計
ObjectGetDouble/ObjectSetDoubleとは何か(非推奨ObjectGet/ObjectSetとの違い)
まず、この2つの関数がどんな役割を持つのかを確認します。
旧関数ObjectGet/ObjectSetがなぜ非推奨になったか
本サイトのオブジェクト系記事でもたびたび触れてきたとおり、
旧来のObjectGet()/ObjectSet()は、
座標・価格(double)も、色・幅(int)も、
同じ関数で一律にdouble型としてやり取りしていました。
・ObjectGet/ObjectSetは公式リファレンスで「非推奨」と明記されている
・型ごとに専用の関数(Integer/Double/String版)が用意されている
ObjectGetDoubleの構文(2つのバリアント)
double ObjectGetDouble( long chart_id, string object_name, int prop_id, int prop_modifier=0 ); bool ObjectGetDouble( long chart_id, string object_name, int prop_id, int prop_modifier, double &double_var );
chart_idは0で現在のチャート、
prop_idはOBJPROP_PRICE等のプロパティ識別子です。
prop_modifierはフィボナッチツールのように、
複数の価格点を持つオブジェクト用の番号です。
水平線のように価格点が1つだけのオブジェクトでは0を指定します。
ObjectSetDoubleの構文(2つのバリアント)
bool ObjectSetDouble( long chart_id, string object_name, int prop_id, double prop_value ); bool ObjectSetDouble( long chart_id, string object_name, int prop_id, int prop_modifier, double prop_value );
引数の並びはObjectGetDoubleとほぼ対になっており、
最後の引数に「設定したい値」を渡す点だけが違います。
マウスでドラッグできる価格ラインの作成
実際に、ドラッグ操作を受け付ける水平線を作ります。
ObjectCreateで水平線を1本作る
ObjectCreate(0, "DraggableAlertLine", OBJ_HLINE, 0, 0, Bid); ObjectSetInteger(0, "DraggableAlertLine", OBJPROP_COLOR, clrOrange); ObjectSetInteger(0, "DraggableAlertLine", OBJPROP_WIDTH, 2);
OBJ_HLINEは水平線オブジェクトで、価格(第6引数)だけを指定すれば描画できます。
ドラッグ可能にするためのOBJPROP_SELECTABLE設定
ObjectSetInteger(0, "DraggableAlertLine", OBJPROP_SELECTABLE, true);
OBJPROP_SELECTABLEがfalseになっていると、
そもそもマウスでクリックして選択することができず、ドラッグ自体が発生しません。
水平線は既定でtrueですが、明示的に指定しておくと事故が起きにくくなります。
ObjectGetDoubleで現在の価格を取得する
double linePrice = ObjectGetDouble(0, "DraggableAlertLine", OBJPROP_PRICE, 0);
OBJPROP_PRICEは水平線の価格プロパティで、これが「今ラインが引かれている価格」
を返します。
CHARTEVENT_OBJECT_DRAGでドラッグ後の価格を取得する
ドラッグされたことをどうやって検知するかを確認します。
OnChartEventの基本構文
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
// ここでイベントの種類(id)ごとに処理を分岐する
}
OnChartEventは、チャート上でクリック・ドラッグ・キー入力等の
イベントが発生するたびに、MT4から自動的に呼び出される関数です。
sparamでドラッグされたオブジェクト名を判定する
if(id == CHARTEVENT_OBJECT_DRAG && sparam == "DraggableAlertLine")
{
// このオブジェクトがドラッグされた
}
CHARTEVENT_OBJECT_DRAGが発生したとき、
sparamには「ドラッグされたオブジェクトの名前」が入ります。
自分が作ったラインの名前と一致するかを確認することで、
他のオブジェクト(水平線を複数引いていた場合など)と区別できます。
ドラッグ後の新しい価格をObjectGetDoubleで取得する
double newPrice = ObjectGetDouble(0, "DraggableAlertLine", OBJPROP_PRICE, 0);
ドラッグが終わった時点で改めてObjectGetDoubleを呼べば、
ユーザーが動かした後の新しい価格が取得できます。
価格到達でアラートを出す処理を組み込む
ラインの価格に実勢価格が到達したときの通知処理を作ります。
前回のBidと比較してクロスを判定する
bool crossedUp = (prevBid < linePrice && Bid >= linePrice); bool crossedDown = (prevBid > linePrice && Bid <= linePrice);
「Bidがラインの価格と完全に一致したか」ではなく、
前回のBidと今回のBidの間にラインの価格を挟んだかどうかで判定すると、
値が1pipsも動かない静かな相場でも取りこぼしません。
一度だけアラートを鳴らすためのフラグ管理
・Alert()に直結すると、価格が上下するたびに何度も鳴ってしまう
・alertedという変数で「鳴らし終えたか」を管理し、以降は鳴らさない
ラインを動かしたらアラート済みフラグをリセットする
if(id == CHARTEVENT_OBJECT_DRAG && sparam == "DraggableAlertLine")
{
alerted = false;
}
CHARTEVENT_OBJECT_DRAGの中でalertedをfalseに戻すことで、
ユーザーがラインを動かした時点で「もう一度見張る」状態に、
自動的に再武装される設計になります。
実際に動くコード全体
ここまでの要素をまとめた、実際に動くインジケーターです。
//+------------------------------------------------------------------+
//| DraggableAlertLine.mq4 |
//| Copyright 2026, FX-EA System Project Creator |
//| https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX-EA System Project Creator"
#property link "https://creator.fx-ea-system-project.com/"
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 0
#define LINE_NAME "DraggableAlertLine"
bool alerted = false;
double prevBid = 0;
int OnInit()
{
if(ObjectFind(0, LINE_NAME) < 0)
{
ObjectCreate(0, LINE_NAME, OBJ_HLINE, 0, 0, Bid);
ObjectSetInteger(0, LINE_NAME, OBJPROP_COLOR, clrOrange);
ObjectSetInteger(0, LINE_NAME, OBJPROP_WIDTH, 2);
ObjectSetInteger(0, LINE_NAME, OBJPROP_SELECTABLE, true);
}
prevBid = Bid;
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
ObjectDelete(0, LINE_NAME);
}
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[])
{
double linePrice = ObjectGetDouble(0, LINE_NAME, OBJPROP_PRICE, 0);
if(!alerted)
{
bool crossedUp = (prevBid < linePrice && Bid >= linePrice);
bool crossedDown = (prevBid > linePrice && Bid <= linePrice);
if(crossedUp || crossedDown)
{
Alert(_Symbol, "の価格が ", DoubleToString(linePrice, _Digits), " へ到達しました");
alerted = true;
}
}
prevBid = Bid;
return(rates_total);
}
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
if(id == CHARTEVENT_OBJECT_DRAG && sparam == LINE_NAME)
{
alerted = false;
Print("ラインが移動されました。新しい価格: ",
DoubleToString(ObjectGetDouble(0, LINE_NAME, OBJPROP_PRICE, 0), _Digits));
}
}
MetaEditorでのコンパイル・実行手順
実際にMT4で動かすまでの手順を確認します。
- MetaEditorで新規カスタムインジケーター「DraggableAlertLine」を作成し、上のコードを貼り付けてコンパイルする
- MT4のナビゲーターからチャートへドラッグ&ドロップで適用する
- チャート上にオレンジ色の水平線が表示されることを確認する
- 水平線をクリックして選択し、上下にドラッグして動かしてみる
- 「エキスパート」タブに移動先の価格を示すPrintの出力が表示されることを確認する
- 価格がラインに到達したら、Alertのポップアップが表示されることを確認する
よくあるエラーと注意点
実装でつまずきやすいポイントをまとめます。
ObjectGetDoubleが0を返す原因
| 原因 | 対処 |
|---|---|
| オブジェクト名のスペルミス | ObjectCreateで作った名前とObjectGetDoubleに渡す名前を定数(#define)で統一する |
| prop_idの指定間違い(OBJPROP_PRICEではなくOBJPROP_PRICE1等) | OBJ_HLINEにはOBJPROP_PRICEのみ存在することを公式リファレンスで確認する |
| OnInitより前にObjectGetDoubleを呼んでいる | オブジェクト作成後に呼び出す順序を守る |
ドラッグしてもCHARTEVENT_OBJECT_DRAGが発火しない原因
OBJPROP_SELECTABLEがfalseに設定されている場合、
そもそもマウスでの選択自体ができず、ドラッグイベントも発生しません。
ObjectSetIntegerでOBJPROP_SELECTABLEを、
trueにしているか確認してください。
MQL4とMQL5の違い
ObjectGetDouble/ObjectSetDouble、
CHARTEVENT_OBJECT_DRAGの関数シグネチャ・定数名は、
MQL4とMQL5で完全に共通です。
現行のMQL4は内部的にMQL5と同じコンパイラ基盤を使っているため、
オブジェクト操作まわりの新しいAPIに関しては、
両者の違いを気にする必要がほとんどない領域の1つです。
よくある質問
ドラッグ可能な価格ラインについて、よく検索される疑問に回答します。
複数の価格ラインを同時にドラッグ対応にできますか?
できます。
ライン名を配列やループで管理し、
OnChartEventのsparamをどのライン名と一致するか、
判定する処理をライン本数ぶん繰り返せば対応できます。
EAの中でこの仕組みを使ってエントリー価格を指定できますか?
可能です。
本記事はアラート専用として紹介しましたが、
ObjectGetDoubleで取得した価格を、
OrderSendの価格として使えば、
「チャート上でドラッグして決めた価格に指値を置く」EAも作れます。
ObjectSetDoubleでラインの価格をプログラム側から動かせますか?
動かせます。
ObjectSetDouble(0, "DraggableAlertLine", OBJPROP_PRICE, 新しい価格);
のように呼び出せば、ユーザーのドラッグを待たずに、
プログラム側からラインの位置を更新できます。
(例: 現在値から常に一定pips上に追従させる等)
【MQL4】ObjectGetDouble・ObjectSetDoubleでドラッグ可能な価格アラートラインを作る方法について解説してみた:まとめ
ObjectGetDouble/ObjectSetDoubleは、
非推奨になった旧ObjectGet/ObjectSetの後継として、
プロパティの型ごとに分かれた現行のAPIです。
CHARTEVENT_OBJECT_DRAGと組み合わせれば、
コードを書き直すことなく、チャート上の操作だけでアラート価格を変更できるツールが作れます。
コメント