【MQL4勉強】サポート・レジスタンスラインを描写するインジケーターをMT4で作ってみよう!

ザフナーラボブログ

サポートライン(=支持線)とは、為替レートが下落から上昇に転じる価格帯に引いた線をいいます。

Support-Line

サポートライン(支持線)

他方、レジスタンスライン(=抵抗線)とは、為替レートが上昇から下落に転じる価格帯に引いた線をいいます。

Resistance-Line

レジスタンスライン(抵抗線)

上に示した画像からも分かるとおり、サポートラインとレジスタンスラインは、以下のように、為替レートの反転の目安として用いることができます。

  • 為替レートがサポートラインに近づいたとき
    為替レートが上昇に転じることを期待して、買いポジションを持つ
  • 為替レートがレジスタンスラインに近づいたとき
    為替レートが下落に転じることを期待して、売りポジションを持つ

一方で、為替レートがサポートラインやレジスタンスラインを突き抜けた場合は、その方向に為替レートが進行していく場合があるため、ブレイクアウトの目安として用いることもできます。

Support-Break

レートがサポートラインを下抜けると、下方向にレートが進行していく

Resistance-Break

レートがレジスタンスラインを上抜けると、上方向にレートが進行していく

つまり、サポートラインとレジスタンスラインは、売買を行っていくうえで、重要なポイントを示しているということができます。

そこで、サポートラインとレジスタンスラインを自動的に引くインジケーター(Support-Resistance.mq4)の作成方法について解説します。

「Support-Resistance.mq4」のロジックは、「フラクタル」(詳細は「こちら」を参照してください。)と同様の考え方によります。

ただし、フラクタルはパラメーターが存在せず、常に5本のローソク足の配置に基づいてインジケーターが表示されることになりますが、「Support-Resistance.mq4」においては、計算に使用するローソク足の本数をパラメーター化し、変更可能としています。

なお、類似のインジケーターとして、「Support and Resistance」というものがあります。

これは、フラクタルを基にサポートラインとレジスタンスラインを引くものであり、計算範囲はフラクタルと同様、常にバー5本分となります。

したがって、換言すれば、「Support-Resistance.mq4」は、「Support and Resistance」にパラメーター設定を加えたもの、ということができます。

1.全体像

MetaTrader4(MT4)でインジケーターを作成するには、以下の手順に従ってプログラムを書いていくことになります。

  1. #property命令を記述する。
  2. インジケーターバッファーの宣言を行う。
  3. 変数の宣言を行う。
  4. init()関数内にインジケーターの基本的な設定を記述する。
  5. start()関数内に具体的な処理内容を記述する。

以下のサンプルコードをダウンロードして、サンプルコードを見ながら記事を読み進めて下さい。

Support-Resistance-Code

2.#property命令の記述

#property命令とは、インジケーターの色、ラインの太さ、インジケーターを表示する場所などの、プログラム全体にかかわる設定を行うものです。

#property命令の詳細については「こちら」を参照してください。

「Support-Resistance.mq4」における、#property命令を記述した部分の解釈を示すと、以下のようになります。

⑴ チャートウィンドウに表示させる

# property indicator_chart_window命令によって、「Support-Resistance.mq4」は、チャートウィンドウに表示されます。

⑵ 2種類のデータを表示させる

「Support-Resistance.mq4」では、以下の2つのデータを表示させます。

  • サポートラインを示す点
  • レジスタンスラインを示す点

したがって、#property indicator_buffers命令には、「2」を指定します。

⑶ 色を指定する

「Support-Resistance.mq4」で表示される2つのデータの表示色を指定します。

  • #property indicator_color1 Aqua
    1番目のインジケーターとしてサポートラインの値を示す点を指定する(後述)ので、#property indicator_color命令には「1」を指定し、表示色を「Aqua」に指定しています。
  • #property indicator_color2 Aqua
    2番目のインジケーターとしてレジスタンスラインの値を示す点を指定する(後述)ので、#proerty indicator_color命令には「2」を指定し、表示色を「Magenta」に指定しています。

3.インジケーターバッファーの宣言

インジケーターバッファーとは、インジケーターの計算に使用するデータを格納しておく配列のことをいいます。

インジケーターバッファーの詳細については「こちら」を参照してください。

「Support-Resistance.mq4」における、インジケーターバッファーを宣言した部分の解釈を示すと、以下のようになります。

Buffer-Support-Resistance

⑴ double Support[];

サポートラインの値を格納していく配列です。

⑵ double Resistance[];

レジスタンスラインの値を格納していく配列です。

⑶ double Support_Point[];

サポートラインの位置を示す値を格納していく配列です。

⑷ double Resistance_Point[];

レジスタンスラインの位置を示す値を格納していく配列です。

4.変数の宣言

変数」の詳細については「こちら」を参照してください。

「Support-Resistance.mq4」においては、以下の項目をパラメーターとして指定します。

  • 上昇(下落)から下落(上昇)に転じているかどうかを判定するバーの本数

上記項目は、インジケーターをチャートに適用した際に任意の値に設定することができるようにするため、以下に示すように、「外部変数」(詳細については「こちら」を参照してください。)として宣言します。

  • extern int Calculate_Bars
    上昇(下落)から下落(上昇)に転じているかどうかを判定するバーの本数

また、「Support-Resistance.mq4」は、以下のような内容になっています。

  • インジケーターをチャートに適用した後の「1」ティック目に実行する計算の範囲と、「2」ティック目以降に行う計算の範囲が異なる(後述)。
  • パラメーターとして指定するバーの本数は「奇数」でなければならない(「フラクタル」(詳細は「こちら」を参照してください。)と同様の考え方を基にしているため。)。

そこで、以下のようなグローバル変数を宣言しています。

  • int Calculated
    インジケーターをチャートに適用した後の「1」ティック目なのか、「2」ティック目以降なのかの場合分けを行うために使用します。
    当該変数に格納されている値が「0」であれば「1」ティック目、「1」であれば「2」ティック目以降であることを意味します。
  • bool Even_Number
    パラメーターとして指定したバーの本数が「奇数」なのか「偶数」なのかを判定するために使用します。
    当該変数に格納されている値が「flase」であれば「奇数」、「true」であれば「偶数」であることを意味します。

5.基本設定の記述

「Support-Resistance.mq4」におけるinit()関数内に記述したコードについて解説します。

Support-Resistance-init

⑴ IndicatorBuffers()とは

IndicatorBuffers()は、MQL4であらかじめ定義されている関数で、インジケーターの計算に使用するバッファーの個数を指定するものです。

IndicatorBuffers()関数の詳細については「こちら」を参照してください。

⑵ IndicatorDigits()とは

IndicatorDigits()とは、MQL4であらかじめ定義されている関数で、インジケーターの値を、小数点以下何桁まで表示させるかを指定するものです。

IndicatorDigits()関数の詳細については「こちら」を参照してください。

⑶ SetIndexBuffer()とは

SetIndexBuffer()とは、MQL4であらかじめ定義されている関数で、各インジケーターバッファーを、インジケーターバッファー領域(データを一時的に蓄えるデータ領域)に割り当てるものです。

SetIndexBuffer()関数の詳細については「こちら」を参照してください。

⑷ SetIndexLabel()とは

SetIndexLabel()とは、MQL4であらかじめ定義されている関数で、データウィンドウにインジケーターの描画線の説明を表示させるものです。

SetIndexLabel()関数の詳細については「こちら」を参照してください。

⑸ SetIndexStyle()、SetIndexArrow()とは

SetIndexStyle()とは、MQL4であらかじめ定義されている関数で、インジケーターの描画スタイル(線orヒストグラム、色など)を設定するものです。

SetIndexStyle()関数の詳細については「こちら」を参照してください。

SetIndexArrow()とは、MQL4であらかじめ定義されている関数で、インジケーターに記号を表示させるために使用するものです。

SetIndexArrow()関数の詳細については「こちら」を参照してください。

6.具体的な処理内容

「Support-Resistance.mq4」のstart()関数内に記述したコードについて解説します。

Support-Resistance-start

⑴ 偶数かどうかをチェックする

「Support-Resistance.mq4」は、「フラクタル」(詳細は「こちら」を参照してください。)と同様の考え方を基にしているため、パラメーターとして指定するバーの本数は、「奇数」でなければなりません。

そこで、インジケーターをチャートに適用した際に、最初にパラメーター「Claculate_Bars」の値が「偶数」となっていないかどうかをチェックし、「偶数」となっている場合は、ポップアップアラートを一度出して、その後の計算は行わないようにしています。

ア 「2」で割り切れるかどうかをチェック

パラメーター「Calculate_Bars」の値が「偶数」の場合は、当該値は「2」で割り切れるということになります。

そこで、MathMod()関数(詳細は「こちら」を参照してください。)を使用して、「Calculate_Bars」の値を「2」で割ったときの余りが「0」となるかどうかをチェックしています。

イ ポップアップアラートを出す

パラメーター「Calculate_Bars」の値が「偶数」だった場合は、Alert()関数(詳細は「こちら」を参照してください。)を使用して、パラメーターの値は「奇数」でなければならない旨のポップアップアラートを出すようにしています。

また、当該アラートは「1」回だけ表示されれば足りるので、ポップアップアラートが「1」度出された後は、変数「Even_Number」の値を「true」にしておきます。

これによって、上記アのif()文(詳細は「こちら」を参照してください。)の条件式に合致しなくなるので、インジケーターをチャートに適用してから「2」ティック目以降は、パラメーター「Calculate_Bars」の値を変更するまで、Alert()関数は実行されなくなります。

⑵ 計算範囲を選択できるようにする

「Support-Resistance.mq4」においては、インジケーターをチャートに適用した後の「1」ティック目に実行する計算の範囲と、「2」ティック目以降に行う計算の範囲が異なるので、IndicatorCounted()関数(詳細は「こちら」を参照してください。)を使用して、以後のswitch()文(詳細は「こちら」を参照してください。)で計算範囲の選択ができるようにしています。

具体的には、

  • IndicatorCounted()関数の戻り値が「0」の場合
    この場合は、インジケーターの値がまだ計算されていないこと、すなわち、インジケーターをチャートに適用していから「1」ティック目であることを意味します。
    そこで、この場合には、変数「Calculated」に「0」を格納するようにしています。
  • IndicatorCounted()関数の戻り値が「正」の場合
    この場合は、インジケーターの値がすでに計算されたことがあること、すなわち、インジケーターをチャートに適用してから「2」ティック目以降であることを意味します。
    そこで、この場合には、変数「Calculated」に「1」を格納するようにしています。

⑶ 実行する計算を振り分ける

switch()文(詳細は「こちら」を参照してください。)の()内に、上記⑵で算出した変数「Calculated」の値を格納することによって、以下のように、実行する計算を振り分けるようにしています。

  • 変数「Calculated」の値が「0」の場合
    インジケーターをチャートに適用してから「1」ティック目に行う計算(=case 0:~break;までの計算)を実行します。
  • 変数「Calculated」の値が「1」の場合
    インジケーターをチャートに適用してから「2」ティック目以降に行う計算(=case 1:~break;までの計算)を実行します。

⑷ 1ティック目に実行する計算

インジケーターをチャートに適用してから「1」ティック目においては、チャートウィンドウ上にあるすべてのバーについて、まだインジケーターの値の計算が実行されていません。

そこで、インジケーターをチャートに適用してから「1」ティック目においては、チャートウィンドウ上にあるすべてのバーについて、サポートラインとレジスタンスラインの値の計算を行います。

ア for()文による繰り返し計算を行う

以下のようにfor()文(詳細は「こちら」を参照してください。)の「初期設定文」、「条件式」及び「再設定式」を記述することによって、チャートウィンドウ上の最古のバーから最新のバーに向けて、サポートラインとレジスタンスラインの位置を示す値を計算するようにしています。

  • 初期設定文
    カウンタ変数「i」に予約変数「Bars」(詳細は「こちら」を参照してください。)を格納する。
    (カウンタ変数は、以後の計算に使用するサポートラインとレジスタンスラインの値を格納する配列のインデックスに相当することになります。)
  • 条件式
    カウンタ変数「i」が「0」になるまで
    (カウンタ変数「i」の値が「0」ということは、インジケーターをチャートに適用した際の最新のバーについてのサポートラインとレジスタンスラインの値を計算することに相当します。)
  • 再設定式
    より古いバーについてサポートラインとレジスタンスラインの値を計算するごとに、カウンタ変数「i」の値を「1」ずつ減らす。
    (これによって、より古いバーからより新しいバーに向けて、サポートラインとレジスタンスラインの値を計算することになります。)
イ 所定の配列に「NULL」を格納する

配列Support_Point[]とResistance_Point[]は、以下に示すように、下落(上昇)から上昇(下落)に転じたバーの最安(高)値を取得する(=サポートラインとレジスタンスラインの位置を確定させる)ために使用する配列なので、それら以外の値は格納しないようにします。

Support-Resistance-Point

Support_Point[]及びResistance_Point[]の要素

そこで、とりあえず、配列Support_Point[]とResistance_Point[]には、値のないことを示す「NULL」を順次格納するようにしています。

ウ バーの位置を算出する

「Support-Resistance.mq4」は、「フラクタル」(詳細は「こちら」を参照してください。)の考え方を基にしているため、以下のバーのインデックスを取得する必要があります。

  • パラメーター「Calculate_Bars」で指定した計算範囲の真ん中に相当するバー
  • パラメーター「Calculate_Bars」で指定した計算範囲における最高値を示現したバー
  • パラメーター「Calculate_Bars」で指定した計算範囲における最安値を示現したバー

パラメーター「Calculate_Bars」で指定した計算範囲における最高値を示現したバーのインデックスは、iHighest()関数(詳細は「こちら」を参照してください。)を使用することによって取得することができます。そして、取得したインデックスを変数「Highest_Index」に格納しています。

また、パラメーター「Calculate_Bars」で指定した計算範囲における最安値を示現したバーのインデックスは、iLowest()関数(詳細は「こちら」を参照してください。)を使用することによって取得することができます。そして、取得したインデックスを変数「Lowest_Index」に格納しています。

パラメーター「Calculate_Bars」で指定した計算範囲における真ん中に相当するバーのインデックスは、以下の図のような関係にあります。

Center_Index

計算範囲の真ん中のバーのインデックス

そこで、MathFloor()関数(詳細は「こちら」を参照してください。)を使用して、パラメーター「Calculate_Bars」の値を「2」で割った値の小数点以下の値を切り捨てたうえで、カウンタ変数「i」の値を加算することで、算出しています。そして、算出したインデックスを変数「Center_Index」に格納しています。

エ サポート・レジスタンスラインの位置を確定させる

変数「Center_Index」に格納されている値と、変数「Lowest_Index」又は「Highest_Index」に格納されている値が等しい場合は、以下の図に示すように、そのインデックスに相当するバーで、レートが下落(上昇)から上昇(下落)に転じていることになります。

Conversion

「Highest_Index」と「Lowetst_Index」で、レートの方向性が転換する

そこで、以下のような処理を実行させています。

  • 「Center_Index」の値が「Lowest_Index」の値と等しいとき
    レートが下落から上昇に転じているので、当該インデックスの安値を配列Support_Point[]に格納しています(後掲の図参照)。
  • 「Center_Index」の値が「Highest_Index」の値と等しいとき
    レートが上昇から下落に転じているので、当該インデックスの高値を配列Resistance_Point[]に格納しています(後掲の図参照)。

    Center-Highest-Lowest

    「高値」・「安値」を、それぞれResistance_Point[]・Support_Point[]に格納する

オ カウンタ変数の再設定を行う

配列Support_Point[]及びResistance_Point[]にサポートライン及びレジスタンスラインの位置を示す値を格納した後は、それぞれの値を基にして、サポートライン及びレジスタンスラインを描画していく処理を、チャートウィンドウ上のすべてのバーについて実行していきます。

そこで、その処理を実行する前に、あらかじめ、カウンタ変数「i」に、予約変数「Bars」(詳細は「こちら」を参照してください。)の値を格納しておきます。

カ while()文による繰り返し計算を行う

上記オの処理により、カウンタ変数「i」には予約変数「Bars」(詳細は「こちら」を参照してください。)の値が格納されています。

したがって、while()文(詳細は「こちら」を参照してください。)の条件式を「iは0以上」とすることによって、最古のバーから最新のバーに向かって、サポートラインとレジスタンスラインが描画されていくことになります(後述のケも参照)。

キ サポートラインを描画させる
  1. 配列Support_Point[]の値が「NULL」ではない場合は、レートが下落から上昇に転じたバーの最安値が格納されていることになり、そこがサポートラインを描画させるべき位置ということになります。
    したがって、当該値を配列Support[]に格納しています。
  2. また、配列Support_Point[]の値が「NULL」であり、かつ、1本前のバーに相当する配列Support[]の要素の値が「正」である場合(=1本前のバーに相当する配列Support[]の要素に値が格納されている場合)は、「新たにレートが下落から上昇に転じたバーが示現していない」ということを意味します。
    そうすると、「上記1.と同じ位置に、サポートラインを継続して描画させていかなければならない」ということになります。
    したがって、上記1.と同じ値を、配列Support[]に格納しています。

以上を図示すると、以下のようになります。

Support_Line_1

Support_Point[]の値をSupport[]に格納し、点を描画する

Support_Line_2

Support[i]にSupport[i+1]の値を格納し、点を描画する

ク レジスタンスラインを描画させる

サポートラインを描画させる論理と同様の論理により、レジスタンスラインを描画させるようにしています。

ケ カウンタ変数の値を減じる

1つのバーについてサポートラインとレジスタンスラインを描画させる処理を行ったら、次のバーについて同様の処理を繰り返しを行うようにするために、カウンタ変数「i」の値を「1」減じています。

⑸ 2ティック目以降に実行する計算

インジケーターをチャートに適用してから2ティック目以降は、チャートウィンドウ上にあるすべてのバーについてインジケーターの値の計算を行う必要はなく、現在のバーから、パラメーター「Calculate_Bars」で設定した本数までの範囲内で、インジケーターの値の計算を行えば足ります。

ア 所定の配列に「NULL」を格納する

インジケーターをチャートに適用してから「2」ティック目以降は、変化が生じるのは現在のバー、すなわち、新たに生成されている最新のバーについてのみです。

したがって、Support_Point[]及びResistance_Point[]には、上記⑷アのように、for()文(詳細は「こちら」を参照してください。)を使用して繰り返し「NULL」を格納するという計算を行う必要はなく、現在のバーに相当する要素についてのみ「NULL」を格納すれば足ります。

イ バーの位置を算出する

上記⑷ウのように、「Support-Resistance.mq4」においては、以下のバーのインデックスを取得する必要があります。

  • パラメーター「Calculate_Bars」で指定した計算範囲の真ん中に相当するバー
  • パラメーター「Calculate_Bars」で指定した計算範囲における最高値を示現したバー
  • パラメーター「Calculate_Bars」で指定した計算範囲における最安値を示現したバー

インジケーターをチャートに適用してから「2」ティック目以降は、現在のバーから、パラメーター「Calculate_Bars」で設定した本数までの範囲内で、インジケーターの値の計算を行えば足りるので、それぞれのバーのインデックスを取得する計算式は、以下のように、上記⑷ウの場合とは異なります。

  • 最高値を示現したバーの場合
    iHighest()関数(詳細は「こちら」を参照してください。)の最後の引数を、「i」ではなく「0」とします。
  • 最安値を示現したバーの場合
    iLowest()関数(詳細は「こちら」を参照してください。)の最後の引数を、「i」ではなく「0」とします。
  • 真ん中に相当するバーの場合
    上記⑷ウの場合とは異なり、カウンタ変数「i」は存在しないので、パラメーター「Calculate_Bars」の値を「2」で割った値に、MathFloor()関数(詳細は「こちら」を参照してください。)を使用するのみとなります。
エ サポート・レジスタンスラインの位置を確定させる

上記⑷エと同様となります。

オ for()文による繰り返し計算を行う

インジケーターをチャートに適用してから「2」ティック目以降は、最新のバーからパラメーター「Calculate_Bars」で指定した本数のバーについてのみ、インジケーターの値の計算を行えば足ります。

そこで、上記⑷カとは異なって、チャートウィンドウ上のすべてのバーを対象としたwhile()文(詳細は「こちら」を参照してください。)ではなく、以下のようにfor()文(詳細は「こちら」を参照してください。)の「初期設定文」、「条件式」、及び「再設定式」を記述することによって、パラメーター「Calculate_Bars」で設定した範囲のうち、最古のバーから最新のバーに向けて、サポートラインとレジスタンスラインの値を計算するようにしています。

  • 初期設定文
    チャートウィンドウ上のバーのインデックスは、現在のバーを「0」として、過去にさかのぼるにつれて「1」、「2」、……と振られています。
    したがって、現在のバーからパラメーター「Calculate_Bars」で指定した本数分さかのぼったバーのインデックスは、「Calculate_Bars-1」となります。
    そこで、カウンタ変数「i」に「Calculate_Bars-1」を格納しています。
  • 条件式
    カウンタ変数「i」が「0」になるまで
    (カウンタ変数「i」の値が「0」ということは、インジケーターをチャートに適用した際の最新のバーについてのサポートラインとレジスタンスラインの値を計算することに相当します。)
  • 再設定式
    より古いバーについてサポートラインとレジスタンスラインの値を計算するごとに、カウンタ変数「i」の値を「1」ずつ減らす。
    (これによって、より古いバーからより新しいバーに向けて、サポートラインとレジスタンスラインの値を計算することになります。)
カ サポートラインを描画させる

上記⑷キと同様です。

キ レジスタンスラインを描画させる

上記⑷クと同様です。