FX自動売買基礎と応用

トレンドラインにおける価格の誤差を確認する方法【MQLプログラミングの基礎】


1.ファイルのひな形を作って接頭辞を設定


この記事では、トレンドラインにおける時間足の違いによる価格の変化を確認する方法について解説します。トレンドラインは斜めに引いて利用することが多いですが、異なる時間足で同じように斜めに引いたつもりでも、時間足によって価格にずれが発生してしまいます。どういうことかイメージするために、現在のローソク足でのトレンドラインの価格を表示するツールを作成し、時間足の違いによる価格のずれを確認していきます。

まずファイルの新規作成で「カスタムインディケータ」を選択し、ファイル名を「PriceTag」とします。「カスタムインディケータのイベントハンドラ」の画面では「OnChartEvent」にチェックを入れ、次の画面で「完了」をクリックすれば、ひな形の完成です。

「カスタムインディケータのイベントハンドラ」の画面

今回はオブジェクトを使うので、ファイル上部のプロパティ「#property indicator_chart_window」の下で接頭辞「PREFIX」を定義しましょう。これを設定しておくと、オブジェクトをまとめて削除することができます。


#define PREFIX "PriceTag_"

そして「Custom indicator initialization function」の下に「Custom indicator deinitialization function」を設けて、OnDeinit関数を使った次のコードを記述します。これでインジケーターをチャートから外したときに関連オブジェクトが消えるようになります。


void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0, PREFIX);
}


2.トレンドラインを検索して価格を表示する関数の作成


続いて、トレンドラインを見つけたときに価格を表示する関数「DrawTag()」を作ります。DrawTag()はティックの更新ごとに動かしたいので、OnCalculate関数内の「//— return value of prev_calculated for next call」の上に配置して実行するようにします。


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[])
{
//---
   DrawTag();
//--- return value of prev_calculated for next call
   return(rates_total);
}

また、トレンドラインを動かしたときにDrawTag()が作動するようにします。OnChartEvent関数内に二つのif文を追加しましょう。「CHARTEVENT_OBJECT_DRAG」はマウスのドラッグを表すチャートイベントで、オブジェクトがドラッグされた(移動された)ときにそのタイプがトレンドラインだったらDrawTag()を実行します。


void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
//---
   if (id == CHARTEVENT_OBJECT_DRAG) {
      if (ObjectGetInteger(0, sparam, OBJPROP_TYPE) == OBJ_TREND) DrawTag();
   }
}


3.指定した位置の価格情報を取得


上記では、トレンドラインを見つけたときに価格を表示する関数「DrawTag()」を作成し、その作動条件を設定することができました。次に、DrawTag()の中身を記述していきます。

「ChartEvent function」の下に「Draw tag function」を設けて、そこにコードを書いていきましょう。for文で全オブジェクトを検索し、トレンドラインだった場合に「ObjectGetValueByShift」で指定した位置の価格情報を取得します。ObjectGetValueByShiftは対象オブジェクトの座標から、指定したバーのシフト数に対応する価格を取得できる関数です。


void DrawTag()
{
   for (int i = 0; i < ObjectsTotal(0, -1); i++) {
      string name = ObjectName(0, i);
      if (ObjectGetInteger(0, name, OBJPROP_TYPE) == OBJ_TREND) {
      double price = ObjectGetValueByShift(name, 0);
   }
}


4.Arrowオブジェクトのサンプルコードを改修


ObjectGetValueByShiftで得た価格情報を、今回はArrowオブジェクトで表示します。Arrowオブジェクトのサンプルコードを、MQL4リファレンスからコピーして使います。MQL4リファレンスの目次にある「Constants, Enumerations and Structures」→「Objects Constants」→「Object Types」をクリックするとオブジェクトの一覧が表示されるので、その中から「OBJ_ARROW」を選択し、あらかじめ用意されている「Create the arrow」のコードをコピーしてファイル下部に貼り付けます。

「//--- set anchor point coordinates if they are not set」から「ResetLastError();」までの4行と、「Print(__FUNCTION__,」「": failed to create an arrow! Error code = ", GetLastError());」の2行は不要なので削除してください。そして値の変化に合わせて位置が変わるように、「if(!ObjectCreate(chart_ID, name, OBJ_ARROW, sub_window, time, price)) {」の下に「ObjectSetInteger(chart_ID, name, OBJPROP_TIME, 0, time);」と「ObjectSetDouble(chart_ID, name, OBJPROP_PRICE, 0, price);」の2行を追記し、時間と価格情報を入れます。

また、初期設定をあらかじめ変更しておきます。「// arrow code」の「arrow_code = 252」を「arrow_code = 6」に、「// arrow color」の「clr = clrRed」を「clr = clrWhite」に、「// arrow size」の「width = 3」を「width = 5」に、「// highlight to move」の「selection = true」を「selection = false」に変更しましょう。これでArrowオブジェクトの設定は完了です。


//+------------------------------------------------------------------+
//| Create the arrow                                                 |
//+------------------------------------------------------------------+
bool ArrowCreate(const long              chart_ID = 0,         // chart's ID
                 const string            name = "Arrow",       // arrow name
                 const int               sub_window = 0,       // subwindow index
                 datetime                time = 0,             // anchor point time
                 double                  price = 0,            // anchor point price
                 const uchar             arrow_code = 6,     // arrow code
                 const ENUM_ARROW_ANCHOR anchor = ANCHOR_BOTTOM, // anchor point position
                 const color             clr = clrWhite,         // arrow color
                 const ENUM_LINE_STYLE   style = STYLE_SOLID,  // border line style
                 const int               width = 5,            // arrow size
                 const bool              back = false,         // in the background
                 const bool              selection = false,     // highlight to move
                 const bool              hidden = true,        // hidden in the object list
                 const long              z_order = 0)          // priority for mouse click
{
//--- create an arrow
   if(!ObjectCreate(chart_ID, name, OBJ_ARROW, sub_window, time, price)) {
      ObjectSetInteger(chart_ID, name, OBJPROP_TIME, 0, time);
      ObjectSetDouble(chart_ID, name, OBJPROP_PRICE, 0, price);
      return(false);
   }
//--- set the arrow code
   ObjectSetInteger(chart_ID, name, OBJPROP_ARROWCODE, arrow_code);
//--- set anchor type
   ObjectSetInteger(chart_ID, name, OBJPROP_ANCHOR, anchor);
//--- set the arrow color
   ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);
//--- set the border line style
   ObjectSetInteger(chart_ID, name, OBJPROP_STYLE, style);
//--- set the arrow's size
   ObjectSetInteger(chart_ID, name, OBJPROP_WIDTH, width);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(chart_ID, name, OBJPROP_BACK, back);
//--- enable (true) or disable (false) the mode of moving the arrow by mouse
//--- when creating a graphical object using ObjectCreate function, the object cannot be
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
   ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, selection);
   ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, selection);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(chart_ID, name, OBJPROP_HIDDEN, hidden);
//--- set the priority for receiving the event of a mouse click in the chart
   ObjectSetInteger(chart_ID, name, OBJPROP_ZORDER, z_order);
//--- successful execution
   return(true);
}


5.価格情報をArrowオブジェクトとして表示


上記では、価格の表示で利用するArrowオブジェクトのサンプルコードを改修して使える状態にしました。続いて、DrawTag()で設定したArrowCreateを使い、現在のローソク足でのトレンドラインの価格を表示できるようにします。

DrawTag()内の「double price = ObjectGetValueByShift(name, 0);」の下に、次のコードを加えます。チャートIDは「0」、名前は「PREFIX + name」、サブウィンドウは「0」、時間は現在時間の「Time[0]」、価格は「price」とします。


ArrowCreate(0, PREFIX + name, 0, Time[0], price);

これでコンパイルしてチャートにセットすると、現在のローソク足でのトレンドラインの価格が表示されます。

価格情報をArrowオブジェクトとして表示


6.同期する2枚のチャートで誤差を比較


今回は分かりやすいように、2枚のチャートを並べて価格のずれを確認します。「トレンドラインを複数のチャートで同期させる方法」の記事で作成したトレンドラインを同期するツール「TrendlineSync」をセットした2枚のチャートで比較してみましょう。

上下のチャートは共に1時間足で表示したもので、この状態ではどちらも「127.961」と同じ価格を示しています。

2枚のチャートを並べて価格のずれを確認

では、上のチャートの時間足を15分足に変更してみましょう。すると価格の表示が「127.949」に変化し、2pips程ずれることが分かります。上位足1本に対し下位足は複数あり、精度の違いによってこのような誤差が発生する仕組みです。誤差はトレンドラインの角度があるほど大きくなります。時間軸を変えてマルチタイムフレームでトレンドラインを利用する場合は、価格に誤差が生じることを覚えておきましょう。

2枚のチャートを並べて価格のずれを確認


7.ソースコード


今回、作成したソースコードは下記の通りです。


//+------------------------------------------------------------------+
//|                                                     PriceTag.mq4 |
//|                        Copyright 2022, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
#property indicator_chart_window
#define PREFIX "PriceTag_"
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0, PREFIX);
}
//+------------------------------------------------------------------+
//| 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[])
{
//---
   DrawTag();
//--- return value of prev_calculated for next call
   return(rates_total);
}
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
//---
   if (id == CHARTEVENT_OBJECT_DRAG) {
      if (ObjectGetInteger(0, sparam, OBJPROP_TYPE) == OBJ_TREND) DrawTag();
   }
}
//+------------------------------------------------------------------+
//| Draw tag function                                                |
//+------------------------------------------------------------------+
void DrawTag()
{
   for (int i = 0; i < ObjectsTotal(0, -1); i++) {
      string name = ObjectName(0, i);
      if (ObjectGetInteger(0, name, OBJPROP_TYPE) == OBJ_TREND) {
         double price = ObjectGetValueByShift(name, 0);
         ArrowCreate(0, PREFIX + name, 0, Time[0], price);
      }
   }
}
//+------------------------------------------------------------------+
//| Create the arrow                                                 |
//+------------------------------------------------------------------+
bool ArrowCreate(const long              chart_ID = 0,         // chart's ID
                 const string            name = "Arrow",       // arrow name
                 const int               sub_window = 0,       // subwindow index
                 datetime                time = 0,             // anchor point time
                 double                  price = 0,            // anchor point price
                 const uchar             arrow_code = 6,     // arrow code
                 const ENUM_ARROW_ANCHOR anchor = ANCHOR_BOTTOM, // anchor point position
                 const color             clr = clrWhite,         // arrow color
                 const ENUM_LINE_STYLE   style = STYLE_SOLID,  // border line style
                 const int               width = 5,            // arrow size
                 const bool              back = false,         // in the background
                 const bool              selection = false,     // highlight to move
                 const bool              hidden = true,        // hidden in the object list
                 const long              z_order = 0)          // priority for mouse click
{
//--- create an arrow
   if(!ObjectCreate(chart_ID, name, OBJ_ARROW, sub_window, time, price)) {
      ObjectSetInteger(chart_ID, name, OBJPROP_TIME, 0, time);
      ObjectSetDouble(chart_ID, name, OBJPROP_PRICE, 0, price);
      return(false);
   }
//--- set the arrow code
   ObjectSetInteger(chart_ID, name, OBJPROP_ARROWCODE, arrow_code);
//--- set anchor type
   ObjectSetInteger(chart_ID, name, OBJPROP_ANCHOR, anchor);
//--- set the arrow color
   ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);
//--- set the border line style
   ObjectSetInteger(chart_ID, name, OBJPROP_STYLE, style);
//--- set the arrow's size
   ObjectSetInteger(chart_ID, name, OBJPROP_WIDTH, width);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(chart_ID, name, OBJPROP_BACK, back);
//--- enable (true) or disable (false) the mode of moving the arrow by mouse
//--- when creating a graphical object using ObjectCreate function, the object cannot be
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
   ObjectSetInteger(chart_ID, name, OBJPROP_SELECTABLE, selection);
   ObjectSetInteger(chart_ID, name, OBJPROP_SELECTED, selection);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(chart_ID, name, OBJPROP_HIDDEN, hidden);
//--- set the priority for receiving the event of a mouse click in the chart
   ObjectSetInteger(chart_ID, name, OBJPROP_ZORDER, z_order);
//--- successful execution
   return(true);
}


本記事の監修者・HT FX


2013年にFXを開始し、その後専業トレーダーへ。2014年からMT4/MT5のカスタムインジケーターの開発に取り組む。ブログでは100本を超えるインジケーターを無料公開。投資スタイルは自作の秒足インジケーターを利用したスキャルピング。

EA(自動売買)を学びたい方へオススメコンテンツ

EA運用の注意点

OANDAではEA(自動売買)を稼働するプラットフォームMT4/MT5の基本的な使い方について、画像や動画付きで詳しく解説しています。MT4/MT5のインストールからEAの設定方法までを詳しく解説しているので、初心者の方でもスムーズにEA運用を始めることが可能です。またOANDAの口座をお持ちであれば、独自開発したオリジナルインジケーターを無料で利用することもできます。EA運用をお考えであれば、ぜひ口座開設をご検討ください。


本ホームページに掲載されている事項は、投資判断の参考となる情報の提供を目的としたものであり、投資の勧誘を目的としたものではありません。投資方針、投資タイミング等は、ご自身の責任において判断してください。本サービスの情報に基づいて行った取引のいかなる損失についても、当社は一切の責を負いかねますのでご了承ください。また、当社は、当該情報の正確性および完全性を保証または約束するものでなく、今後、予告なしに内容を変更または廃止する場合があります。なお、当該情報の欠落・誤謬等につきましてもその責を負いかねますのでご了承ください。

この記事をシェアする

ホーム » FX自動売買基礎と応用 » トレンドラインにおける価格の誤差を確認する方法【MQLプログラミングの基礎】