FX

MQL4のObjectCreateでFX自動売買の線を描画・確認する方法

コードで描画した水平線を確認するイメージ

MQL4のObjectCreateは、チャートに水平線、トレンドライン、文字などのオブジェクトを作る関数です。FX自動売買の判定位置を画面へ示すときに使えますが、線を描いたことと注文を出したことは別の処理です。まずは発注しない検証用チャートで、一つの水平線を作るところから確かめましょう。

実装で大切なのは、名前、種類、表示先、座標を決め、作成後に存在とプロパティを読み戻すことです。本記事ではMQL4の仕様に沿って、引数、ObjectFindの判定、座標と見た目の違い、同名衝突や後片付けまで説明します。手動で線を引く操作ではなく、コードから描画を管理したい方向けの内容です。

この記事のポイント
  • 種類ごとに必要な座標と表示先を整理できる
  • ObjectFindの0を未発見と取り違えずに判定できる
  • 水平線を一つ作成して価格を読み戻す流れが分かる
  • 同名衝突・非表示・削除範囲を分けて点検できる

MQL4のObjectCreateでFX自動売買を描画

時刻と価格の座標に水平線を置く模式図
操作場面のイメージ画像です。実際の画面ではありません。

作成する対象と表示先を決める

ObjectCreateは、指定した名前と種類の描画オブジェクトをチャートに作成します。銘柄の注文を送る関数ではなく、画面上の線や文字を扱うための機能です。例えばEAが判定に使った基準価格を水平線で示せば、計算値と目で見た位置を比較しやすくなります。

引数にはチャートIDを指定する書式と、現在のチャートを使う書式があります。最初はチャートIDを0とし、プログラムを実行した現在のチャートだけを扱うと、表示先を追いやすくなります。別チャートを扱う場合は、そのIDがどの銘柄・時間足のチャートに対応するのかも確認します。

sub_windowは表示するウィンドウの番号です。0がメインチャートで、指標などのサブウィンドウは1以降になります。存在しない番号を指定すると作成に失敗するため、「指標の下へ出したい」という意図だけで1を固定せず、対象のウィンドウがあるかを先に確認してください。

名前は同じチャートのサブウィンドウを含めて一意である必要があります。別のサブウィンドウなら同じ名前でも区別できる、とは考えません。何を作るかに加えて、誰がその名前を管理するかまで決めておくと、複数のEAや手描きオブジェクトとの衝突を減らせます。

書式と表示先の仕様はMetaQuotesのObjectCreateリファレンスを参照してください。MQL5には同名の関数がありますが、戻り値や処理の待ち方を含めて説明が異なるため、MQL4用の実装へ混ぜないようにします。

種類によって座標の意味が変わる

水平線とトレンドラインでは、必要な基準点が違います。水平線は主に価格の位置、トレンドラインは二つの時刻と価格の組で位置を決めます。同じObjectCreateでも、種類を変えれば引数の意味を確認し直す必要があります。

種類主な基準実装前の確認点
OBJ_HLINE価格どの価格へ水平線を置くか
OBJ_VLINE時刻どの日時に縦線を置くか
OBJ_TREND二つの時刻と価格二点の選び方と延長の設定
OBJ_TEXT時刻と価格どの足のどの位置へ文字を置くか
OBJ_LABEL画面の隅からの距離基準の隅とピクセル距離
水平線・トレンドライン・ラベルの位置基準を比較する模式図
操作場面のイメージ画像です。実際の画面ではありません。

時刻しか使わない縦線でも、関数の呼び出しでは時刻と価格を組にして渡す必要があります。一方、OBJ_LABELはObjectCreateへ渡した時刻・価格で位置を決めるものではなく、基準の隅と画面内の距離をプロパティで設定します。文字を表示する二種類のオブジェクトを混同すると、スクロール後の動きも想定と変わります。

水平線の公式例では、OBJ_HLINE、表示先0、時刻0、指定価格という形で作成しています。まずこの小さな構成で、入力した価格と線の位置が合うかを確かめると、複数のアンカーを使う図形より原因を絞りやすくなります。

手動のトレンドラインで二点の意味を確認したい場合は、MT4のトレンドラインの引き方と編集が参考になります。ただし、手動で選んだ二点をEAが自動的に選べるわけではありません。コードで扱う場合は、二点を選ぶ条件を別途定義します。

名前の衝突を作成前に調べる

実装例でよく使われるlineやlabelという短い名前だけでは、他のプログラムが作ったものと重なりやすくなります。自分のプログラムを識別する接頭辞と役割を含め、検証用ならNCE_ObjectDemo_HLineのように、何のためのオブジェクトか分かる名前にします。

作成前にObjectFindで同名のものがあるか調べます。この関数が返すのは真偽値ではなく、見つかったサブウィンドウの番号です。メインチャートで見つかれば0なので、if(ObjectFind(...))のように真偽値として扱うと、存在するのに見つからないと取り違える原因になります。

名前の衝突を防ぐため対象を区別するイメージ
操作場面のイメージ画像です。実際の画面ではありません。

見つかったと判断する条件は0以上、見つからない場合は負の値です。今回のような確認用の例では、同名があれば処理を中止し、既存のものを触りません。自分が作った線か不明な状態で、名前が同じだから削除して作り直すという処理にはしないほうがよいでしょう。

実運用で作り直しが必要なら、作成済みを更新するのか、一度削除するのか、何もしないのかを仕様として決めます。毎ティック違う名前を作るとオブジェクトが増え続けるため、現在の状態を一つの名前で表すのか、履歴として足ごとに残すのかも分けて設計します。

公式のObjectFindの戻り値を確認すると、0の扱いを明確にできます。名前の上限は63文字なので、識別情報をすべて連結して長くし過ぎず、役割が重ならない範囲で簡潔にします。

作成と装飾と再描画を分ける

ObjectCreateで形を作った後、色や太さなどは対応するプロパティへ設定します。整数や色を扱うObjectSetInteger、価格などを扱うObjectSetDouble、文字列を扱うObjectSetStringを、値の種類に応じて使い分けます。

作成に成功しても、その後の色設定に失敗することは別の段階として扱います。複数の関数を続けて呼んだ最後にだけGetLastErrorを見ると、どこで失敗したかが分かりにくくなります。必要な設定ごとに結果を確認し、エラーがあれば対象の名前と操作を一緒に残します。

ChartRedrawはチャートの再描画を促す関数です。色や位置の変更後に表示を更新したい場合に使いますが、間違った座標を正すものではありません。線が見えないから何度も再描画するより、まず対象ウィンドウ、座標、色、表示条件を確認します。

また、MQL4で現在のチャートへ作成する場合と、別チャートへコマンドを送る場合では戻り値の意味に違いがあります。別チャートではキューへ追加できたという結果と、作成が実行された結果を分け、ObjectFindやプロパティ取得で確認します。最初の例を現在チャートだけに絞るのは、この違いを混ぜないためです。

MQL4のObjectCreateを作成後に確認

ObjectCreateで一本の水平線を作るイメージ
操作場面のイメージ画像です。実際の画面ではありません。

一つの水平線を作る確認例

以下は、現在のチャートの一本前の終値を読み、その価格へ水平線を一つ作成するスクリプト例です。同名が存在する場合は中止し、注文は送信しません。作成した線は確認のため残るので、既存のEAを載せていないデモ用チャートで試してください。

#property strict
void OnStart()
{
   string name = "NCE_ObjectDemo_HLine";
   if(iBars(Symbol(),Period()) < 2)
   {
      Print("Not enough history");
      return;
   }
   if(ObjectFind(0,name) >= 0)
   {
      Print("Name already exists: ",name);
      return;
   }
   ResetLastError();
   double price = iClose(Symbol(),Period(),1);
   int price_error = GetLastError();
   if(price_error != 0 || price <= 0)
   {
      Print("Price read failed: ",price_error);
      return;
   }
   ResetLastError();
   if(!ObjectCreate(0,name,OBJ_HLINE,0,0,price))
   {
      Print("Create failed: ",GetLastError());
      return;
   }
   if(!ObjectSetInteger(0,name,OBJPROP_COLOR,clrBlue))
      Print("Color setting failed: ",GetLastError());
   ObjectSetInteger(0,name,OBJPROP_HIDDEN,false);
   ChartRedraw(0);
   int window = ObjectFind(0,name);
   double actual = 0;
   ResetLastError();
   bool read_ok = ObjectGetDouble(0,name,OBJPROP_PRICE,0,actual);
   if(window != 0 || !read_ok)
   {
      Print("Readback failed: ",GetLastError());
      return;
   }
   Print(name," expected=",DoubleToString(price,Digits),
         " actual=",DoubleToString(actual,Digits));
}

このコードは説明用で、利用者のMT4環境でコンパイル・実行済みという意味ではありません。MetaEditorで確認し、実行後はログに出た価格、オブジェクト一覧、画面上の線を照合してください。価格が0以下の場合に見送る条件は、この例で扱う正のFX価格を前提にしています。

OBJPROP_HIDDENをfalseにするのは、確認用のオブジェクト名を一覧から見つけやすくするためです。この設定に失敗した場合でも「すべて表示」で見つかるかなどを確認できます。色の設定だけ失敗した場合は作成そのものが取り消されるわけではないため、実行前の状態へ自動的に戻ったとは判断しないでください。

水平線の作成仕様はMetaQuotesのOBJ_HLINE公式例を基準にしています。コードを動かすだけでなく、作ったものが何という名前で、どのウィンドウの何の価格にあるかまで確認すると、次の更新処理も設計しやすくなります。

存在確認と価格の読み戻しを行う

作成後は、まずObjectFindで対象の名前が見つかり、想定したサブウィンドウにあるか確かめます。次にObjectGetDoubleで価格を読み、入力した価格と比較します。画面に青い線が見えるだけでは、たまたま別の線が同じ場所にある可能性を除けないためです。

作成した線の価格プロパティを読み戻す模式図
操作場面のイメージ画像です。実際の画面ではありません。

ObjectGetDoubleには、値を直接返す形式と、成否を真偽値で返して変数に値を受け取る形式があります。上の例では後者を使い、読取に成功したかと、受け取った価格が何かを分けて確認します。取得失敗時の値を、意図した価格として利用しないことが大切です。

線が同じ価格に重なっている場合は、オブジェクト一覧の名前とプロパティを使って対象を確認します。マウスで選んだ線がどれか分からないままドラッグすると、別のEAが使う基準線を動かしてしまう可能性があります。自分の検証用のものを名前で識別してから操作してください。

読み戻した価格とログの表示桁もそろえます。実数の内部表現による小さい差をどう扱うかは、銘柄の刻みや用途に合わせて決めます。価格を丸めた見た目だけで完全一致を主張したり、逆に意味のない小数差だけで誤描画と判断したりしないようにします。

この仕組みは、EAが計算した基準を描画して人が照合する場面に役立ちます。ただし、描いた線が正しい価格にあることと、その価格を使った売買手法が有効なことは別です。描画の確認が済んだ後に、判定条件や取引コストを含む検証へ進みましょう。

見えないときは順番に切り分ける

最初は、作成関数がfalseを返したのか、作成には成功したが画面に見えないのかを分けます。falseなら名前、存在するサブウィンドウ、引数を確認します。成功しているならObjectFindで存在を確認し、価格や座標を読み戻してから表示条件へ進みます。

状態先に調べる項目避けたい対処
作成時にfalse同名・表示先・引数とエラー原因を見ず作成を連打する
名前はあるが線が見えない価格範囲・ウィンドウ・色毎回別名で大量作成する
一覧に名前がない一覧の全表示とHIDDEN属性存在しないと即断する
文字が画面外にあるOBJ_TEXTとOBJ_LABELの座標差時刻とピクセルを混ぜる
別の線が動く名前と対象チャートID手描き線を同名で上書きする

背景と線の色が近かったり、表示している価格範囲から線が離れていたりすると、存在していても見つけにくくなります。水平線の例では一本前の終値を使っているため比較しやすいですが、時間がたって画面を大きく移動した場合は、対象価格が表示範囲内にあるか確認してください。

文字の種類を変える場合は、OBJ_TEXTが時刻と価格、OBJ_LABELが画面の隅からの距離を基準にする違いへ戻ります。チャートをスクロールしたときに一緒に動いてほしいのか、常に画面の隅へ置きたいのかを先に決めると、適切な種類を選びやすくなります。

ソースコードの更新が反映されない場合は描画条件だけでなく、編集したファイルとMT4が読み込む実行ファイルの対応も確認します。MT4のコンパイルと更新確認の手順を参考に、古いコードを実行したまま設定を調べ続けていないか確かめましょう。

MQL4のObjectCreateは管理まで決める

一つのオブジェクトの位置を変えるなら、作成し直す前に更新の方法を検討します。ObjectMoveなどで座標を変更できる種類もありますが、どのアンカー番号を変えるかは種類に依存します。作成、更新、削除を別の処理として分けると、必要以上に線を増やす実装を避けられます。

他の線を残して対象の線だけを選択するイメージ
操作場面のイメージ画像です。実際の画面ではありません。

後片付けは、自分が作成した名前だけを対象にします。チャート上の全オブジェクトを消す処理を、水平線一つの検証のために使わないでください。手描きの分析線や他のEAが管理する表示が同じチャートにある可能性があります。削除にはObjectDeleteの仕様を確認し、対象名と削除後の存在を照合します。

このスクリプトの例では線を残すため、確認を終えたらオブジェクト一覧からNCE_ObjectDemo_HLineを選び、その一つだけを削除します。再実行で同名の中止メッセージが出た場合も、前回の線が残っていることを先に確認し、他のオブジェクトへ手を広げないようにします。

FX自動売買に組み込む際は、起動時に作るのか、条件成立時に作るのか、終了時に消すのかを決めます。名前、表示先、座標、読取確認、後片付けまで一続きで設計してから、描画を判定の確認手段として使ってください。

EA作成ツールの検証範囲を確認する

生成コードの動作テスト・コンパイル結果と、その限界 →記事内の戦略や個別のEAの収益性を検証した結果ではありません。

学んだルールを、形にしてみよう。

EA作成ツールを開く ↗