[MQL]チャートの右端に短い水平線を引く方法

以前書いた水平線を表示するインジケーターの作成方法の記事で「チャートの右端に短い水平線を引くにはどうしたらいい?」という質問をいただきました。

そんな場合のMQLのコードの書き方を説明します。

短い水平線を表示するとは?

MQLで下図の様にチャートの右端に短い水平線を引くという意味です。

動作時の様子

経緯:頂いた質問内容

この記事を書いた経緯は、以前公開した記事(初めてのインジケータ作成③ 水平線を表示するインジケータを作る)で下のご質問をいただいたからです。

頂いた質問1

↑ふむふむ、短い水平線を引く方法が知りたいとのことですね。

管理人からの返答1

↑質問内容について、私からの質問返し。

すぐに下のご返答いただきました。

頂いた質問2

↑なるほど、チャートの右端に短い水平線が並ぶようなイメージですね。あと、価格の表示も必須のようですね。

管理人の返答2

↑私からの返答。

という経緯で、チャートの右端に短い水平線を引く方法の説明に至りました。

実現方法

まず今回頂いた希望内容を整理すると、以下の4点に集約されます。

  1. チャートの右端に短い水平線を引きたい
  2. 水平線には価格表示が必要
  3. 水平線は1本ではない(MAX200本想定)
  4. 色や太さなどが変えられるようにしたい

これをMQLで実現する方法を考えていきます。

まず1つ目の「短い水平線」についてですが、MT4の標準の水平線は長さを指定することができません。ですので、何か別のもので短い水平線を作ることになります。代用できそうなものとしては、トレンドラインや角度指定ライン、インジケータバッファなどがあります。今回は直感的に分かりやすいトレンドラインを使って実現します。

トレンドラインを水平に引き、始点と終点の座標をうまく指定することで右端に並ぶようにするというイメージです。

二つ目の価格表示については、トレンドラインには水平線のように価格を表示する機能が備わっていないので、テキストラベルを生成して価格表示することにします。

三つ目は特に問題ありません。必要な本数だけラインを生成する処理を繰り返せばOKです。

四つ目も特に問題ありません。変数を使って色などをを指定すればOKです。ここでは簡単に入力パラメーターで色と太さを指定することにします。

実現方法をまとめると「水平なトレンドラインをチャートの右端に生成し、価格をテキストラベルで表示する。」となります。

インジを作成

ということで作ったのが下のサンプルインジです。このインジをドル円のチャートに適用すると最初の図で示したように短い水平線が表示されます。(ラインはBid価格とBid価格+0.5の2本表示)


//+------------------------------------------------------------------+
//|                                   Mi_short_horizontal_sample.mq4 |
//|                                                     minagachi FX |
//|                                            https://minagachi.com |
//+------------------------------------------------------------------+
#property copyright "minagachi FX"
#property link      "https://minagachi.com"
#property version   "1.00"
#property strict
#property indicator_chart_window

input int   width = 2;           // ラインの太さ
input color clr   = clrYellow;   // ラインの色
input int   gap   = 10;          // 現在バーより何本右にラインを引くか

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
  //オブジェクト用の変数を宣言
  string   line_name;   // トレンドラインの名前
  string   text_name;   // テキストの名前
  double   price;       // 価格
  string   text_desc;   // テキストの表記
  datetime time_start;  // ラインのスタート(時刻)
  datetime time_end;    // ラインの終了(時刻)

  //変数に共通の値を代入
  time_start = Time[0] + ChartPeriod(0) * 60 * gap;  //最新バーからgap本右の時刻を算出
  time_end   = D'2050.01.01 00:00';                  //2050年1月1日0時 これは適当

  // ---1本目------------------------
  // トレンドラインをBid価格に生成
  line_name  = "Line_1";
  price = Bid;
  ObjectCreate(0, line_name, OBJ_TREND, 0, time_start, price, time_end, price); //ラインを生成
  ObjectSetInteger(0, line_name, OBJPROP_COLOR, clr);                           //ラインの色を設定
  ObjectSetInteger(0, line_name, OBJPROP_WIDTH, width);                         //ラインの太さを設定

  // 価格テキストを生成
  text_name = "Text_1";
  text_desc = (string)NormalizeDouble(price, 3);                       //価格を文字列に変換
  ObjectCreate(0, text_name, OBJ_TEXT, 0, time_start, price);          //価格テキストを生成
  ObjectSetInteger(0, text_name, OBJPROP_COLOR, clr);                  //価格テキストの色を設定
  ObjectSetString(0, text_name, OBJPROP_TEXT, text_desc);              //価格テキストの表記を設定
  ObjectSetInteger(0, text_name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);   //価格テキストを左下で位置合わせ

  // ---2本目------------------------
  // トレンドラインをBid価格+0.5に生成
  line_name  = "Line_2";
  price = Bid + 0.5;
  ObjectCreate(0, line_name, OBJ_TREND, 0, time_start, price, time_end, price);
  ObjectSetInteger(0, line_name, OBJPROP_COLOR, clr);
  ObjectSetInteger(0, line_name, OBJPROP_WIDTH, width);

  // 価格テキストを生成
  text_name = "Text_2";
  text_desc = (string)NormalizeDouble(price, 3);
  ObjectCreate(0, text_name, OBJ_TEXT, 0, time_start, price);
  ObjectSetInteger(0, text_name, OBJPROP_COLOR, clr);
  ObjectSetString(0, text_name, OBJPROP_TEXT, text_desc);
  ObjectSetInteger(0, text_name, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER);

  return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator termination function                            |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
  //インジ終了時にオブジェクトを削除
  ObjectDelete("Line_1");
  ObjectDelete("Line_2");
  ObjectDelete("Text_1");
  ObjectDelete("Text_2");
}

//+------------------------------------------------------------------+
//| 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[])
{
  //新規バー発生時のみラインを右にずらす処理を行う
  if(IsNewBar() == true){
    //オブジェクト用の変数宣言
    string   line_name;
    string   text_name;
    double   price;
    datetime time_start = Time[0] + ChartPeriod(0) * 60 * gap;

    //1本目を右に移動
    line_name  = "Line_1";
    text_name = "Text_1";
    price = ObjectGetDouble(0, line_name, OBJPROP_PRICE1);
    ObjectMove(0, line_name, 0, time_start, price); //ラインを右にずらす
    ObjectMove(0, text_name, 0, time_start, price); //価格テキストを右にずらす

    //2本目を右に移動
    line_name  = "Line_2";
    text_name = "Text_2";
    price = ObjectGetDouble(0, line_name, OBJPROP_PRICE1);
    ObjectMove(0, line_name, 0, time_start, price); //ラインを右にずらす
    ObjectMove(0, text_name, 0, time_start, price); //価格テキストを右にずらす
  }
  return(rates_total);
}
//+------------------------------------------------------------------+
//| Functions                                                        |
//+------------------------------------------------------------------+
// 新規バーかどうかを判定する関数
bool IsNewBar(){
  static datetime dt = Time[0];
  if(Time[0] != dt){
    dt = Time[0];
    return (true);
  }
  return (false);
}

似たような処理が何度も出てくる、少し無駄のあるコードですね、、、。以下で処理のポイントを説明します。

インジ適用時の処理(OnInit)

ここでは、ラインや価格のテキストを生成しています。

ラインやテキストをチャートの右端に表示するため、最新バーから10本分(入力変数gapで変更可)の時刻を取得しています。time_start = Time[0] + ChartPeriod(0) * 60 * gap;の箇所です。この時刻座標の取得については過去記事([MQL]最新ロウソク足より右にオブジェクトを描画する場合の時刻(座標)指定方法)に考え方を書いてあります。

補足

ユーザーがラインやテキストに触れないようにするには、ObjectSetInteger()関数でOBJPROP_SELECTABLEプロパティを設定します。

ティック受信時の処理(OnCalculate)

ここでは、新規のバーが発生したタイミングかどうかを判定し、新規バー発生時ならばラインと価格テキストをバー1本分右にずらす処理をしています。

この処理を入れないとバーが生成されるたびに水平線がだんだん左にずれてきてしまいます。

まとめ

チャートの右端に短い水平線を引く方法を説明しました。

説明をかなり端折りました、、、。また余裕ができたら書き足すかもしれません。

コメント

この記事へのコメント(8 件)

  • 水平さんより

    さっそく、記事を拝見させていただきました。お仕事が早くて、驚きました。

    なるほど、トレンドラインを水平にして、取得する時刻座標で長さを調整すると考えればできるわけですね。
    ここに着眼するというのは、素人ではとてもできませんでした。

    試行錯誤しながらも、サンプルをMT4に表示してみました。色の変更やラインの種類、太さの変更もメタエディター上から問題なくできました。
    ラインの色も、「clr2」「clr3」と最初に設定してみると、複数の色を表示することができました。

    「input int gap = 10; // 現在より何本右にラインを引くか」で位置を調整するので、チャートを拡大、縮小すると、ローソクの太さによって表示位置が変わってしまいますね。
    これは仕方がないものと思いました。デフォルトの10を6にしたら、拡大縮小してもほどよい位置に収まっています。

    あとは細かいことですが、「110.320」などのように小数点第3位が0になる場合は、0は表示されずに「110.32」となるようでした。
    また、「110.320」といったテキストの下にラインが引かれますが、ライン自体にマウスを当てると、1~3ポイント数値が異なっていることが多いようです。

    どちらも小さなことなので、実用上は全然問題にならないものです。

    1本目「トレンドラインを~生成」「価格テキストを生成」の部分をコピーして繰り返し、ラインを48本表示してみました。
    週明け月曜日には、実際に動くチャートで見てみたいと思います。

    こういうタイプの水平線は、これまでネットでは見たことがなかったので、なかなか画期的ではないかと思います。

    ありがとうございました。

  • 管理人ですさんより

    水平さんへ
    さっそくカスタマイズしていただいているようでなによりです。
    チャートの拡大でラインの位置が変わってしまう件については確かにそうですね。別の手段としては、チャートの右端から例えば100pxのX座標を取得して、そのX座標を時刻に換算した位置にラインを引けば、常にチャートの右から100pxの位置にラインが引けます。長くなるので詳細は省きますが興味があればChartGetInteger()やChartXYToTimePrice()などの関数を調べてみてください。
    ラインにマウスを重ねたときの価格と微妙に値が違う件は、、、MT4のトレンドラインの仕様でそうなってしまいます。ラインの価格を正確に入れてもだめなんですよね。紛らわしいのでマウスを重ねたときに数字が表示させないようにした方がいいかもです。表示させない方法はこの記事にあります。参考まで→「ツールチップを非表示にする方法
    良いインジになるといいですね。では。

  • 水平さんより

    月曜日から、実際に動く相場で使ってみています。
    4時間足以上の大きい時間足では見られないのですが、1時間足以下の比較的短い時間足になると、時間の経過とともに水平線がだんだん左に伸びてきて、気が付くとローソク足の中に紛れ込んでいることもあります。
    ですので、気づいたたびに、一度他の時間足に切り替えて元に戻すと直るのですが、その後もまた時間とともに伸びてきます。
    スケールを固定したら、なくなるのかもしれませんが、基本的に固定はしないので、どうも現状では一定の位置に表示することは難しいみたいです。
    多少手間ではありますが、チャート全面に水平線が引かれた状態よりはすっきりしています。

  • 管理人ですさんより

    水平さんへ
    コードミスったかな?と思って複数のFX会社のMT4で1分足~4時間足で放置してみましたが、私の環境ではラインが左に伸びてくるということはありませんでした。
    カスタマイズ状況が分からないので正確なことは言えませんが、おそらくOnCalculateの処理がうまく走っていないと推測されます。可能であればコードを見直してみてください(オブジェクト名の指定あたりが怪しい気がします)。またはカスタマイズ前のインジで動作を見るのも手です。

  • 水平さんより

    お手数をおかけいたしました。見直してみましたら、やはりOnCalculateの設定が、ちゃんとできていませんでした。再度、設定し直して動かしましたら、左に伸びなくなりました。ご教示いただき、ありがとうございました。

  • 管理人ですさんより

    水平さんへ
    うまく動いたようで良かったです。ほっとしました。結果のご連絡ありがとうございました。

  • saiさんより

    ポジション持った時の
    オーダーラインや損切ラインなども
    こういう感じで短く表示されるといいなー
    それで、そのラインにバツ印があって
    クリックをすると
    決済ができるなんていう
    商品があったら買いたいなー

    ほんと、オーダーライン、文字邪魔で。。。
    ラインもあんなに長いのいらなくて
    右側に短くあったほうがよいとおもうのです

    できたら、ラインの長さ調整なんかができたらいいなー

  • 管理人ですさんより

    saiさんへ
    コメントありがとうございます。
    saiさんのトレードではオーダーラインが邪魔になっているようですね。私はあまり邪魔に感じたことが無いので、トレードスタイルによってニーズはいろいろだなーと思います。
    有償もお考えのようですので、ネットで探せばプログラム作成代行の業者が見つかると思いますよ。(ちなみに私は作成代行は受けておりません。)