FX自動売買基礎と応用

レジスタンスラインとサポートラインの候補となるラインを表示する方法


描画プロパティで2種類のラインを定義


この記事では、チャート上にレジスタンスラインとサポートラインの候補となるラインを表示する方法を紹介します。内容としては、MT4に最初から入っているビル・ウィリアムズ系のインジケーター「Fractals」で記される転換ポイントの位置に、点線を描くというものです。

まずファイルの新規作成で「カスタムインディケータ」を選択したあと、ファイル名を「FractalsLine」としてパラメーターを追加します。今回はバーの計算本数を限定したいので、「BARS」という名前で初期値を「1000」に設定します。

パラメーターを追加

「カスタムインディケータのイベントハンドラ」の画面では、「OnTimer」「OnChartEvent」のどちらにもチェックを入れずに次へ進み、「カスタムインディケータの描画プロパティ」画面のプロット欄でデータを格納するバッファーを登録します。

今回は上側と下側の2種類のラインを描きたいので、それぞれ登録しましょう。上側のラインのラベルを「UPPER」、タイプを「Arrow」、カラーを「Red」に、下側のラインのラベルを「LOWER」、タイプを「Arrow」、カラーを「DodgerBlue」に設定し、「完了」をクリックすれば、ひな形の完成です。

「カスタムインディケータの描画プロパティ」画面


「SetIndexArrow」で使用する記号を設定


ひな形のままだとうまく表示してくれないので、インジケーターをチャートにセットした際、1回のみ実行されるOnInit関数内のコードを書き換えます。

「PlotIndexSetInteger」の2行を、表示させる記号の種類を設定する「SetIndexArrow」に変えましょう。記号の種類を表す番号は、小さい点に該当する「158」とします。なお「PlotIndexSetInteger」は、MT5でコード等を指定する場合の方法です。


SetIndexArrow(0, 158);	
SetIndexArrow(1, 158);

また、バッファーの名前が「UPPERBuffer」「LOWERBuffer」と少し長いので、該当する4か所をそれぞれ「UPPER」「LOWER」に変更します。これでOnInit関数部分のコードは完成です。


double         UPPER[];
double         LOWER[];
SetIndexBuffer(0, UPPER);
SetIndexBuffer(1, LOWER);


iFractals関数で値動きの頂点を取得


続いて、OnCalculate関数の配下に実行する処理に関する式を書き入れます。設定したバーの本数分計算させるようにfor文を作り、iFractals関数を使ってどの頂点に値があるかを調べます。「MODE_UPPER」で上側の、「MODE_LOWER」で下側の頂点が得られます。


for (int i = MathMin(Bars - 2, BARS); i >= 0; i--) {
      double fr_U = iFractals(NULL, 0, MODE_UPPER, i);
      double fr_L = iFractals(NULL, 0, MODE_LOWER, i);

これで点を表示する位置は得られますが、点が表示された場合はそのときの高値や安値が入り、点が表示されていない場合は0が返ってきます。if文を使い「fr_U」が0ではなかった場合に「UPPER[i]」に「fr_U」を、それ以外の場合は一本前の値を入れるようにします。「LOWER」側も同様に記述すればOKです。


if (fr_U != 0) {
   UPPER[i] = fr_U;
} else UPPER[i] = UPPER[i + 1];
if (fr_L != 0) {
   LOWER[i] = fr_L;
} else LOWER [i] = LOWER[i + 1] ;

これでコンパイルしてチャートにセットすると、ウィリアムズ系インジケーターの「Fractals」で示される転換ポイントの位置に点線が引かれます。画像左のチャートが「Fractals」をセットしたもの、右側のチャートがここで作った「FractalsLine」をセットしたものです。

転換ポイントの位置に点線


ラインを停止させる処理を追加


続いて、終値が上側のラインを上抜いた場合と下側のラインを下抜いた場合に、そこでラインの描画を停止させるよう、「else if」で条件を追加します。


else if (Close[i] < UPPER[i + 1]) UPPER[i] = UPPER[i + 1];
else if (Close[i] > LOWER[i + 1]) LOWER[i] = LOWER[i + 1];

これでコンパイルすると、ラインが終値で抜かれた場合は、そのローソク足でラインの描画が停止します。チャートを見ると、ラインがローソク足の実体をまたいでいないことが分かります。

ラインがローソク足の実体をまたいでいない


ラインの延長機能を追加


この状態のままでは、新しいラインが作られると同時に前のラインが途切れてしまいます。これを、終値で抜かれるまではラインを延長するように改修しましょう。

そのためには、トレンドラインオブジェクトを利用します。MQL4リファレンスの目次にある「Constants, Enumerations and Structures」→「Objects Constants」→「Object Types」をクリックするとオブジェクトの一覧が表示されます。その中から「OBJ_TREND」を選択し、あらかじめ用意されているコードをコピーして、ファイルの下部に貼り付けます。

「//— set anchor points’ coordinates if they are not set」から「ResetLastError();」までの4行と、「Print(__FUNCTION__,」「”: failed to create a trend line! Error code = “,GetLastError());」の2行は不要なので削除してください。また、「selection = true」のところを「selection = false」に修正します。


//+------------------------------------------------------------------+ 
//| Create a trend line by the given coordinates                     | 
//+------------------------------------------------------------------+ 
bool TrendCreate(const long            chart_ID=0,        // chart's ID 
                 const string          name="TrendLine",  // line name 
                 const int             sub_window=0,      // subwindow index 
                 datetime              time1=0,           // first point time 
                 double                price1=0,          // first point price 
                 datetime              time2=0,           // second point time 
                 double                price2=0,          // second point price 
                 const color           clr=clrRed,        // line color 
                 const ENUM_LINE_STYLE style=STYLE_SOLID, // line style 
                 const int             width=1,           // line width 
                 const bool            back=false,        // in the background 
                 const bool            selection=true,    // highlight to move 
                 const bool            ray_right=false,   // line's continuation to the right 
                 const bool            hidden=true,       // hidden in the object list 
                 const long            z_order=0)         // priority for mouse click 
  { 
//--- create a trend line by the given coordinates 
   if(!ObjectCreate(chart_ID,name,OBJ_TREND,sub_window,time1,price1,time2,price2)) 
     { 
      return(false); 
     } 
//--- set line color 
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr); 
//--- set line display style 
   ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style); 
//--- set line width 
   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 line 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); 
//--- enable (true) or disable (false) the mode of continuation of the line's display to the right 
   ObjectSetInteger(chart_ID,name,OBJPROP_RAY_RIGHT,ray_right); 
//--- 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); 
  }

次に、オブジェクトを使うので接頭辞を定義します。ファイル上部のプロパティ「#property indicator_width2 1」の下に、次のコードを追記しましょう。


#define  PREFIX "FractalsLine_"

そして、OnDeinit関数を使って、計算のたびに関連オブジェクトを毎回リセットするようにします。


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

OnCalculate関数配下の最初のfor文の上には、次のコードを加えます。これで「PREFIX」という文字が入ったオブジェクトは毎回削除されます。


ObjectsDeleteAll(0, PREFIX);


トレンドラインでラインを延長


ラインの延長機能を追加するために接頭辞を定義し、計算のたびに関連オブジェクトを毎回リセットするようにOnDeinit関数を加えました。それに合わせる形で、OnCalculate関数配下の実行処理のコードを改修していきます。

まず、延長用のトレンドラインをいつ引くかを指定します。今回は、新しい転換ポイントが出たときに、その前のラインを引き始める形としたいので、「UPPER[i] = fr_U;」の下に次のコードを加えましょう。


if (Close[i] < UPPER[i + 1]){

そしてその下に、延長する上側のトレンドラインに関するコードを追記します。


TrendCreate(0, PREFIX + "U_" + (string)i, 0, Time[i], UPPER[i + 1], Time[iEnd], UPPER[i + 1], clrRed, STYLE_DOT);

終点側の時間を検索する必要があるので、新しい点が出現したときにそこから先を検索するよう、上記コードの上にfor文を加えます。また、if文を使って「Close[j]」が点を上回ったら、そのときの値を格納してfor文終了という形にします。


int iEnd = 0;
for (int j = i - 1; j >= 0; j--){
   if (Close[j] > UPPER[i + 1]){
      iEnd = j;
      break;
   }
}

これで上側のトレンドラインは完成です。同じように下側のトレンドラインに関するコードを次のように記述しましょう。


if (Close[i] > LOWER[i + 1]){
   int iEnd = 0;
   for (int j = i - 1; j >= 0; j--){
      if (Close[j] < LOWER[i + 1]){
         iEnd = j;
         break;
      }
   }
   TrendCreate(0, PREFIX + "L_" + (string)i, 0, Time[i], LOWER[i + 1], Time[iEnd], LOWER[i + 1], clrDodgerBlue, STYLE_DOT);
}

これでコンパイルすると、レジスタンスラインとサポートラインの候補となるラインが延長され、使いやすくなります。

ラインが延長


ソースコード


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


//+------------------------------------------------------------------+
//|                                                 FractalsLine.mq4 |
//|                        Copyright 2021, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   2
//--- plot UPPER
#property indicator_label1  "UPPER"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot LOWER
#property indicator_label2  "LOWER"
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrDodgerBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

#define  PREFIX "FractalsLine_"
//--- input parameters
input int      BARS = 1000;
//--- indicator buffers
double         UPPER[];
double         LOWER[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
   SetIndexBuffer(0, UPPER);
   SetIndexBuffer(1, LOWER);
//--- setting a code from the Wingdings charset as the property of PLOT_ARROW
   SetIndexArrow(0, 158);
   SetIndexArrow(1, 158);

//---
   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[])
{
//---
   ObjectsDeleteAll(0, PREFIX);
   for (int i = MathMin(Bars - 2, BARS); i >= 0; i--) {
      double fr_U = iFractals(NULL, 0, MODE_UPPER, i);
      double fr_L = iFractals(NULL, 0, MODE_LOWER, i);

      if (fr_U != 0) {
         UPPER[i] = fr_U;
         if (Close[i] < UPPER[i + 1]){
            int iEnd = 0;
            for (int j = i - 1; j >= 0; j--){
                if (Close[j] > UPPER[i + 1]){
                   iEnd = j;
                   break;
                }
            }
            TrendCreate(0, PREFIX + "U_" + (string)i, 0, Time[i], UPPER[i + 1], Time[iEnd], UPPER[i + 1], clrRed, STYLE_DOT);
         }  
      } else if (Close[i] < UPPER[i + 1]) UPPER[i] = UPPER[i + 1];

      if (fr_L != 0) {
         LOWER[i] = fr_L;
         if (Close[i] > LOWER[i + 1]){
            int iEnd = 0;
            for (int j = i - 1; j >= 0; j--){
                if (Close[j] < LOWER[i + 1]){
                   iEnd = j;
                   break;
                }
            }
            TrendCreate(0, PREFIX + "L_" + (string)i, 0, Time[i], LOWER[i + 1], Time[iEnd], LOWER[i + 1], clrDodgerBlue, STYLE_DOT);
         }  
      } else if (Close[i] > LOWER[i + 1]) LOWER[i] = LOWER[i + 1];

   }
//--- return value of prev_calculated for next call
   return(rates_total);
}

//+------------------------------------------------------------------+
//| Create a trend line by the given coordinates                     |
//+------------------------------------------------------------------+
bool TrendCreate(const long            chart_ID = 0,      // chart's ID
                 const string          name = "TrendLine", // line name
                 const int             sub_window = 0,    // subwindow index
                 datetime              time1 = 0,         // first point time
                 double                price1 = 0,        // first point price
                 datetime              time2 = 0,         // second point time
                 double                price2 = 0,        // second point price
                 const color           clr = clrRed,      // line color
                 const ENUM_LINE_STYLE style = STYLE_SOLID, // line style
                 const int             width = 1,         // line width
                 const bool            back = false,      // in the background
                 const bool            selection = false,  // highlight to move
                 const bool            ray_right = false, // line's continuation to the right
                 const bool            hidden = true,     // hidden in the object list
                 const long            z_order = 0)       // priority for mouse click
{
//--- create a trend line by the given coordinates
   if(!ObjectCreate(chart_ID, name, OBJ_TREND, sub_window, time1, price1, time2, price2)) {
      return(false);
   }
//--- set line color
   ObjectSetInteger(chart_ID, name, OBJPROP_COLOR, clr);
//--- set line display style
   ObjectSetInteger(chart_ID, name, OBJPROP_STYLE, style);
//--- set line width
   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 line 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);
//--- enable (true) or disable (false) the mode of continuation of the line's display to the right
   ObjectSetInteger(chart_ID, name, OBJPROP_RAY_RIGHT, ray_right);
//--- 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自動売買基礎と応用 » レジスタンスラインとサポートラインの候補となるラインを表示する方法