English Русский Español Português
preview
初級から中級まで:インジケーター(III)

初級から中級まで:インジケーター(III)

MetaTrader 5 |
32 2
CODE X
CODE X

前回の「初級から中級まで:インジケーター(II) 」では、非常に基本的で実践的かつ完全に機能する移動平均の実装方法を紹介しました。しかし、あの記事で示した内容はMQL5プログラミングの世界への簡単な導入に過ぎません。素材自体は基本的でシンプルかつストレートフォワードな内容です。しかし、私たちにはもっと多くのことができるのです。

ここで提示する概念を理解するよう努めてください。コードをただコピーするだけではなく、自分で理解することが重要です。自分にできないからといって、他の誰にもできないわけではありません。概念を理解することは、コードを理解することよりも重要です。コードは書き手によって変わりますが、概念は常に不変だからです。今回は非常にシンプルな内容から始めます。というのも、ここで学ぶことは特定の機能を追加すると非常に複雑になる可能性があるからです。


1つのインジケーターと複数の図形表現

すでに誰かがプログラミングしている様子や、市場で利益を得るためのシステムやオペレーショナルセットアップを作ろうとしているのを目にしたことがあるでしょう。多くのシステムでは、複数の移動平均線を使用することが一般的で、場合によっては逆順で適用されることもあります。また、チャネルシステム、たとえば有名なボリンジャーバンドは、2つの移動平均線に基づいており、1本は上限バンドを、もう1本は下限バンドを表します。しかし、ここでの目的はそのようなシステムを市場でどのように使うかを説明することではありません。私たちの目標は、同じようなことをシンプルかつ実践的に実装する方法を示すことです。

ボリンジャーバンドを例にすると(もちろん他の何でも構いません)、通常2本または3本の線があります。そのうち1本はチャネルの内側平均を表します。しかし今回はシンプルにするため、2本の線だけを使い、任意の本数の線を実装する方法を理解しやすくします。まず、以下のコードを使用します。

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. double   gl_buffer[];
11. //+------------------------------------------------------------------+
12. int OnInit()
13. {
14.    SetIndexBuffer(0, gl_buffer, INDICATOR_DATA);
15. 
16.    return INIT_SUCCEEDED;
17. };
18. //+------------------------------------------------------------------+
19. 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 &TickVolume[], const long &Volume[], const int &Spread[])
20. {
21.    for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
22.        gl_buffer[c] = High[c];
23. 
24.    return rates_total;
25. };
26. //+------------------------------------------------------------------+

コード01

このコードを実際に実行してチャートに表示した場合の挙動をここで示す必要はありません。これは前回および前々回の記事で詳細に説明済みだからです。今回注目すべきは、イベントハンドラ関数、つまりこの場合はOnCalculate関数で何がおこなわれているかです。ここでは明示的に最高値を使用していることがわかります。言い換えれば、各バーの高値に沿った図形表現の線が描かれることになります。なぜなら、平滑化計算はおこなっていないからです。もちろん、移動平均の計算は画面上に表示される曲線を滑らかにすることを目的としており、計算に使用される複数の値の平均を作成します。しかし、それを説明するには数学的な解説が必要であり、本記事の範囲を超えます。

さて、コード01で示したこのインジケーターは完全に機能します。ここで注意すべきは、OnCalculate関数の拡張版を使用している点です。その理由はこれから明らかになります。さて質問です。チャートに2本目の図形表現の線を追加するにはどうすればよいでしょうか。たとえば、各バーの安値を表示したい場合です。新しいインジケーターを作り、コードの22行目でHighではなくLowを使えばよいと思われるかもしれません。その通りです。この方法は間違いではなく、確かに動作します。

しかし、この方法ではチャート上に2つの別々のインジケーターが存在することになり、少し複雑になります。細かい点ですが、それぞれのインジケーターは1本の図形表現線しか扱えません。そこで、もっと良い方法があります。2つのインジケーターを1つのコードに統合するのです。このやり方を示すのが本トピックの目的です。最初は複雑に見えるかもしれませんが、ここで示す内容を理解できれば、複数のグラフィカル表現線を持つインジケーターを自由に作れるようになります。なお、今回はあくまで最もシンプルな方法に焦点を当てます。後ほど、ご希望に応じて、より高度な手法も紹介します。

そこで、コード01を修正して2本目のグラフィカル表現線を作ります。手順を1つずつ示すので、誰でも理解しながら進めることができます。

まず最初におこなうのは、新しい図形表現データを保持するバッファを作成することです。使用しているDRAW_LINEタイプは、1つのグラフィカル表現情報につき1つのバッファが必要であることを思い出してください。その結果、以下のようになります。

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. double   gl_buff_max[],
11.          gl_buff_min[];
12. //+------------------------------------------------------------------+
                   .
                   .
                   .

コード02

コード02は、これから実装しようとしている内容の一部を示しています。手順を1つずつ進めることで理解しやすくなります。ここで注意すべきは、10行目でバッファ名を変更し、11行目で新しいバッファを追加している点です。これにより、2本目のグラフィカル表現線の実装を開始したことになります。次のステップは、すべて正しく実装できるように、少し速めに進めます。その後、以下のようなコードが得られます。

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         1
08. #property indicator_plots           1
09. //+----------------+
10. double   gl_buff_max[],
11.          gl_buff_min[];
12. //+------------------------------------------------------------------+
13. int OnInit()
14. {
15.    SetIndexBuffer(0, gl_buff_max, INDICATOR_DATA);
16.    SetIndexBuffer(1, gl_buff_min, INDICATOR_DATA);
17. 
18.    return INIT_SUCCEEDED;
19. };
20. //+------------------------------------------------------------------+
21. 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 &TickVolume[], const long &Volume[], const int &Spread[])
22. {
23.    for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
24.    {
25.       gl_buff_max[c] = High[c];
26.       gl_buff_min[c] = Low[c];
27.    }
28. 
29.    return rates_total;
30. };
31. //+------------------------------------------------------------------+

コード03

さて、ここが本題です。しかし、このコードにはまだ小さな問題があり、解決する必要があります。まずは、この問題が何であり、なぜ発生するのかを理解しましょう。16行目では新しいインデックスを作成しています。MetaTrader 5が管理し、監視するインジケーター内のすべてのバッファには、固有のインデックスが必要です。16行目が定義されると、26行目のようにバッファを使用できるようになります。

このバッファは、図形表現システムで使用され、さまざまな機能を果たすことができます。今回は、チャート上の特定要素を表示するためのデータを格納するタイプのみを使用します。コード03はコンパイル可能です。しかし、チャートに適用すると、結果は次のようになります。

図01

ここではどうして最小値の図形表現線しか表示されないのでしょうか。これは、MetaTrader 5に対して、このインジケーターには図形表現用のバッファが1つしかないと伝えているためです。これは07行目と08行目で確認できます。しかし実際にはバッファが2つ、表示すべき線も2本あります。そのため、07行目と08行目で指定されている情報を変更するだけで対応可能です。この場合、コードを以下のように修正します。

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrBlack
06. //+----------------+
07. #property indicator_buffers         2
08. #property indicator_plots           2
09. //+----------------+
10. double   gl_buff_max[],
11.          gl_buff_min[];
12. //+------------------------------------------------------------------+
                   .
                   .
                   .

コード04

ここで注意すべきは、先ほど述べた行だけを変更した点です。しかし、インジケーターをチャートに適用すると、結果は次のようになります。

図02

「またですか?今度こそ本当に理解できません。コードは2本の線を表示するはずでは?なぜ1本しか見えないのですか?」落ち着いてください、読者の皆さん。慌てる必要はありません。大丈夫です。1本しか表示されない理由は、2本目の線に色が設定されていないからです。これを確認するには、インジケーターの設定を見てみましょう。

アニメーション01

ここで注目すべきは、2本目の線には色が設定されていないという点です。色を割り当てようとしても、表示されません。この問題を解決するには、コンパイラに対して2本目の線を確保して作成するよう指示する必要があります。そのためには、再度コードを修正する必要があります。修正方法は以下の通りです。

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_LINE
05. #property indicator_color1          clrRed
06. //+----------------+
07. #property indicator_type2           DRAW_LINE
08. #property indicator_color2          clrGreen
09. //+----------------+
10. #property indicator_buffers         2
11. #property indicator_plots           2
12. //+----------------+
13. double   gl_buff_max[],
14.          gl_buff_min[];
15. //+------------------------------------------------------------------+
                   .
                   .
                   .

コード05

コード05で追加された内容を確認しましょう。視覚的に分かりやすくするために、異なる色を使用しています。そのため、インジケーターをチャートに適用すると、次のように表示されます。

図03

同じインジケーター内に異なる図形表現線を実装するのがいかに簡単か、お分かりいただけたでしょうか。重要なのは、自分が何をしているのかを理解しながら、要素を段階的に追加していくことです。今回は特別な計算をおこなっていないため、これらの線が交差することはありません。構造としては、バンド系インジケーターを実装する場合とほぼ同じです。違いは、一方の線があるバンドの値を受け取り、もう一方が別のバンドの値を受け取る点です。その結果、有名なボリンジャーバンドのような構造を作ることも可能になります。このテーマは非常に興味深いと思いませんか。

ここまでの知識だけでも、さまざまなタイプやスタイルのインジケーターを作成できるようになっているはずです。しかし、このプログラミング分野は非常に面白いため、さらに深く掘り下げる前にひとつ試してみませんか。図03のインジケーターを、線の色が変化するように変更したいと思いませんか。難しそうだと感じられるかもしれません。しかし、本当に難しいのでしょうか。それとも、まだどのように進めればよいか分からないだけでしょうか。それでは見ていきましょう。ここからは新しいトピックに進みます。


図形表現における色付きの線

人々の関心を引き、最も興奮させる要素のひとつが、色が変化するラインを持つインジケーターです。これまで私たちは、単色を使用する非常にシンプルな仕組みを作成してきました。しかし、色を切り替えることはどうでしょうか。特にMQL5プログラミングを始めたばかりの方には、とても複雑そうに思えるかもしれません。その気持ちはよく分かります。しかし、学習を始めたばかりであっても、これから示す内容に興味を持つことは十分に可能です。そして、いいえ、複数の色でラインをグラフィカルに表示するインジケーターの作成は難しくありません。単に少しアプローチが異なるだけです。

具体的なイメージを持っていただくために、前のトピックで実装したコードを基に考えてみましょう。図03の結果を表示するコードには、以下のような内容が含まれているはずです。

//+------------------------------------------------------------------+
#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
#property indicator_type1           DRAW_LINE
#property indicator_color1          clrRed
//+----------------+
#property indicator_type2           DRAW_LINE
#property indicator_color2          clrGreen
//+----------------+
#property indicator_buffers         2
#property indicator_plots           2
//+----------------+
double   gl_buff_max[],
         gl_buff_min[];
//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer(0, gl_buff_max, INDICATOR_DATA);
   SetIndexBuffer(1, gl_buff_min, INDICATOR_DATA);

   return INIT_SUCCEEDED;
};
//+------------------------------------------------------------------+
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 &TickVolume[], const long &Volume[], const int &Spread[])
{
   for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
   {
      gl_buff_max[c] = High[c];
      gl_buff_min[c] = Low[c];
   }

   return rates_total;
};
//+------------------------------------------------------------------+

コード06

コード06は、コード01に加えたすべての修正の結果であり、チャート上に2本のラインを描画できるようになっています。ここから、これらのラインをマルチカラー表示にするには、次の手順に従います。

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_COLOR_LINE
05. #property indicator_color1          clrMaroon, clrTomato, clrBlue
06. //+----------------+
07. #property indicator_type2           DRAW_COLOR_LINE
08. #property indicator_color2          clrGreen, clrPaleGreen
09. //+----------------+
                   .
                   .
                   .

コード07

ここで、コード06とコード07を比較してみましょう。図形表現に使用するオブジェクトタイプを、DRAW_LINEからDRAW_COLOR_LINEへ変更している点に注目してください。この変更により、各ラインのcolorプロパティに複数の色を指定できるようになります。指定できる色の数は任意であり、MQL5ドキュメントによれば最大64色まで設定可能です。実際、1本目のラインでは3色、2本目では2色を宣言しています。ただし、使用する色は自由に選択できます。しかし、これだけでは不十分です。MetaTrader 5に私たちの意図を正しく理解させるために、さらにいくつかの実装が必要です。

ここで重要なポイントです。マルチカラーのグラフィックシステムを使用する場合、追加のバッファが必要になります。これは、ドキュメント内の次の図で確認できます。

図04

ご覧のとおり、ハイライトされているすべてのポイントにはカラーバッファが必要です。このバッファがなければ、MetaTrader 5はどの色を使用すべきか判断できません。したがって、次におこなうべき変更は、バッファ宣言部分です。これは以下のコードスニペットで確認できます。

                   .
                   .
                   .
09. //+----------------+
10. #property indicator_buffers         4
11. #property indicator_plots           2
12. //+----------------+
13. double   gl_buff_max[],
14.          gl_buff_min[],
15.          gl_color_max[],
16.          gl_color_min[];
17. //+------------------------------------------------------------------+
                   .
                   .
                   .

コード08

コードスニペット08では、実際にバッファを定義しています。ここで注意していただきたいのは、10行目で4つのバッファが必要であると指定している点です。しかし、グラフィカルに描画するのは2本のラインだけなのに、なぜ4つも必要なのでしょうか。その理由は、表示する値用のバッファが1つ、そして色を指定するためのバッファがもう1つ必要だということです。これを理解するために、2つの値を持つ小さな構造体を想像してください。MetaTrader 5は実際には構造体を使用していませんが、そのように考えると分かりやすくなります。MetaTrader 5がこの種のモデリングに構造体を使用していないため、結果として2つのバッファが必要になります。そして今回は2本のラインを描画するため、最終的に必要なバッファ数は4つになります。これらはコードスニペット08の30行目以降で宣言されています。

ここまで来れば、あとは最後のステップだけです。その内容を、次のスニペットで示します。

                   .
                   .
                   .
17. //+------------------------------------------------------------------+
18. int OnInit()
19. {
20.     SetIndexBuffer(0, gl_buff_max, INDICATOR_DATA);
21.     SetIndexBuffer(1, gl_color_max, INDICATOR_COLOR_INDEX);
22.     SetIndexBuffer(2, gl_buff_min, INDICATOR_DATA);
23.     SetIndexBuffer(3, gl_color_min, INDICATOR_COLOR_INDEX);
24. 
25.     return INIT_SUCCEEDED;
26. };
27. //+------------------------------------------------------------------+
28. 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 &TickVolume[], const long &Volume[], const int &Spread[])
29. {
30.     double  mhs = 0,
31.             mhi = 0,
32.             ml = 0;
33.     const double desv = 0.01;
34. 
35.     for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
36.     {
37.         gl_color_max[c] = (mhi > High[c] ? 0 : (mhs < High[c] ? 1 : 2));
38.         mhs = mhi = gl_buff_max[c] = High[c];
39.         mhs += (mhs * desv);
40.         mhi -= (mhi * desv);
41.         gl_color_min[c] = (ml < Low[c] ? 0 : 1);
42.         ml = gl_buff_min[c] = Low[c];
43.     }
44. 
45.     return rates_total;
46. };
47. //+------------------------------------------------------------------+

コード09

コードスニペット09で何をおこなっているのかを説明する前に、このインジケーターを任意の銘柄のチャートに適用した結果を確認してみましょう。以下の画像をご覧ください。

図05

ここで表示されている内容は、あくまでデモンストレーション目的です。このインジケーターは純粋に教育目的で作成されています。初期化フェーズのコードはほとんど変更されていないことが分かります。追加されたのは21行目と23行目のみです。しかし、これらの新しい行が何をしているのかを正しく理解することが非常に重要です。まず、各バッファにはそれぞれ固有の識別子がある点に注目してください。そこに何を格納するかは関係ありません。各バッファは固有の識別子を持たなければなりません。そうでなければ、MetaTrader 5はそれらを使用する際に混乱します。

このケースでは、特定の順序で宣言することが極めて重要です。つまり、次のデータバッファを宣言する前に、あるグラフィカル表現ラインで使用するすべてのデータバッファを宣言しなければなりません。ここにはカラーバッファも含まれます。データバッファやカラーバッファを論理的でない順序で宣言すると、意図した結果は得られません。ここでは宣言順序に十分注意してください。順序は最終結果に直接影響します。初期化が完了した後は、MetaTrader 5によってトリガーされるCalculateイベントを処理する手続きに集中できます。

ここではいくつかの計算とチェックをおこなっていることに注目してください。これは、コード07で定義した色のうち、どの色を画面に描画する際に使用するかをMetaTrader 5に伝えるためです「でも待ってください。どうやってそれを指定しているのですか。ここには数値しかなく、コード07では色の値が定義されていました。MetaTrader 5はどの色を使うと分かるのですか?」

ここで重要なのは、以前の記事で説明した「配列」の概念です。コード07で定義しているのは色の配列です。各色は特定の配列インデックスに格納されています。そのため、21行目と23行目ではINDICATOR_COLOR_INDEX列挙子を使用しています。ここで指定しているのは色そのものではなく、特定の配列内の色インデックスです。では、どの配列でしょうか。コード07には2つの配列があります。MetaTrader 5はどちらを使用するのでしょうか。

ここで、先ほど説明した「順序」の概念が再び重要になります。通常、この種の図形表現は単一形式(1つのインジケーター、1本のライン)で使用されることが多いため、MetaTrader 5は表現タイプの識別子に直接関連付けられたカラースキームを使用します。混乱するかもしれませんが、04行目と05行目には識別子1があり、07行目と08行目には識別子2があります。したがって、グラフィックに表現されるインジケーターに値をリンクすると、コンパイラーはこの識別子を利用して、どのカラースキームを適用すべきかを判断します。

この仕組みを理解しやすくするために、コード07ではそれぞれ異なる数の色を宣言しています。実際にコードを書いて試してみると、より明確に理解できるでしょう。

この部分は少し混乱しやすいかもしれません。なぜなら、すべてを静的に定義し、さらに複数の図形表現ラインを同時に扱っているからです。しかし実際に使ってみると、これらの要素の宣言方法や利用方法は非常にシンプルであることが分かります。

ユーザーがカラースキームを変更したい場合は、次のようなインターフェースにアクセスすることになります。

図06

コード07の05行目および08行目でおこなった宣言により、ユーザーは複数の色を設定できるようになります。そのため、インターフェースはできる限り明確かつシンプルであることが望まれます。コード自体が特定の運用において非常に有用であっても、インターフェースが分かりにくければ、ユーザー体験は悪くなってしまいます。

コードは付録として提供しますので、このようなケースをどのように扱うかをぜひ学習してください。ただし、本日の記事を締めくくる前に、もう1つ別のインジケーターについて触れておきたいと思います。このインジケーターは、適用方法によってはバンドインジケーターにもなり、移動平均クロスオーバーインジケーターにもなり得るものです。混乱を避けるため、この内容は新しいトピックとして解説します。


DRAW_FILLINGインジケーター

このインジケーターは非常に興味深いものです。実装方法によっては、移動平均クロスオーバーインジケーターにもなり、バンドインジケーターにもなり得ます。しかし、初心者プログラマが混乱しやすいのは、まさにその宣言方法にあります。このタイプのインジケーターがいかに簡単に宣言して使用できるかを理解していただくために、本記事の冒頭で提示したコード06を出発点とします。そこから進めることで、DRAW_FILLINGインジケーターで何を実現しようとしているのかが、より明確になります。

コード06を基に、DRAW_FILLINGインジケーターを理解するための修正をおこないます。基本的な構造は以下のとおりです。

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_type1           DRAW_FILLING
05. #property indicator_color1          clrRed, clrGreen
06. //+----------------+
07. #property indicator_buffers         2
08. #property indicator_plots           1
09. //+----------------+
10. double   gl_buff_max[],
11.          gl_buff_min[];
12. //+------------------------------------------------------------------+
13. int OnInit()
14. {
15.     SetIndexBuffer(0, gl_buff_max, INDICATOR_DATA);
16.     SetIndexBuffer(1, gl_buff_min, INDICATOR_DATA);
17. 
18.     return INIT_SUCCEEDED;
19. };
20. //+------------------------------------------------------------------+
21. 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 &TickVolume[], const long &Volume[], const int &Spread[])
22. {
23.     for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
24.     {
25.         gl_buff_max[c] = Open[c];
26.         gl_buff_min[c] = Close[c];
27.     }
28. 
29.     return rates_total;
30. };
31. //+------------------------------------------------------------------+

コード10

「興味深いですね。コード06からの変更は非常に少ないように見えます。しかし、いくつか疑問があります。たとえば、Calculateイベントを処理する手続き内で、なぜopen価格とclose価格を使用しているのですか?」これは、コード10で最大値と最小値として扱われている値のクロス、つまり反転を発生させるためです。読者の皆さんに注意していただきたいのは、一定の間隔でSellバーが発生し、また別のタイミングでBuyバーが発生するという点です。

このDRAW_FILLINGインジケーターを、両面にプリントが施された布のようなものだと想像してください。15行目と16行目で定義されたバッファの値が交差すると反転が発生し、MetaTrader 5は布の片面またはもう片面を表示します。その布に表示される色は05行目で宣言されています。つまり、領域を一方の色、またはもう一方の色で塗り分けることができます。クロスや反転が発生しなければ、05行目で定義されたいずれか一方の色だけが表示されることになります。

しかし、ここで小さな注意点があります。コード10は非常にシンプルですが、チャートに適用すると次の図のように表示されます。

図07

見た目としてはあまり魅力的ではなく、計算およびグラフィカルに表現されている情報の種類によっては、かなり混乱を招く可能性があります。ただし、05行目で宣言した内容により、ユーザーは一定の設定をおこなうことができます。

図08

つまり、用途によっては、このDRAW_FILLINGタイプのインジケーターは非常に有用です。しかし、図07で見られるような表示上の特性から、多くの場合、このインジケーターはメインチャート上ではなく、別ウィンドウに表示されます。ここで次のように思う方もいるかもしれません。「だんだん複雑になってきました。ようやくカラーインジケーターの作り方を理解し始めたばかりなのに、今度は別ウィンドウに表示する話ですか。情報が多すぎて、かなり勉強しなければなりませんね。」

ご安心ください。見た目ほど難しくはありません。MetaTrader 5用に設計されたMQL5には、非常に興味深く実用的な機能が数多く用意されています。

その一つが、インジケーターを別ウィンドウに配置する機能です。ただし、このウィンドウは依然としてメインチャートと連動しています。これを実現する最も簡単な方法のひとつは、インジケーターコードに特定の1行を追加し、チャートに適用された際にMetaTrader 5が新しいウィンドウ、つまりサブウィンドウを開くべきであると理解できるようにすることです。修正後の構造は次のとおりです。

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property indicator_separate_window
05. //+----------------+
06. #property indicator_type1           DRAW_FILLING
07. #property indicator_color1          clrRed, clrGreen
08. //+----------------+
09. #property indicator_buffers         2
10. #property indicator_plots           1
11. //+----------------+
12. double   gl_buff_max[],
13.          gl_buff_min[];
14. //+------------------------------------------------------------------+
15. int OnInit()
16. {
17.     SetIndexBuffer(0, gl_buff_max, INDICATOR_DATA);
18.     SetIndexBuffer(1, gl_buff_min, INDICATOR_DATA);
19. 
20.     return INIT_SUCCEEDED;
21. };
22. //+------------------------------------------------------------------+
23. 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 &TickVolume[], const long &Volume[], const int &Spread[])
24. {
25.     for (int c = (prev_calculated > 0 ? prev_calculated - 1 : 0); c < rates_total; c++)
26.     {
27.         gl_buff_max[c] = Open[c];
28.         gl_buff_min[c] = Close[c];
29.     }
30. 
31.     return rates_total;
32. };
33. //+------------------------------------------------------------------+

コード11

コード10とコード11の違いは、04行目の有無のみです。コード10には存在せず、コード11には追加されています。このコードをコンパイルし、MetaTrader 5でチャートに追加すると、以前は混乱を招いていた図07の表示が、次のようになります。

図09

図09の表示は、以前よりもはるかにシンプルです。ただし、最初はこのチャートの解釈に戸惑うユーザーもいるかもしれません。


まとめ

本記事では、さまざまな形で応用可能な2種類のインジケーターの扱い方を解説しました。目的は、自身のニーズに適したアプリケーションを作成できるようになることです。一見するとシンプルな内容に見えるかもしれませんが、創造性と探究心を持って取り組めば、本記事の内容が他のインジケータータイプ、たとえばDRAW_SECTION、DRAW_HISTOGRAM、DRAW_ARROW、DRAW_ZIGZAG、DRAW_BARS、DRAW_CANDLESへも拡張できることが理解できるはずです。これらはすべて、本記事で扱った仕組みと同様の原理で動作します。今回は2種類、正確にはDRAW_COLOR_LINEを含めれば3種類を扱いましたが、それは本質的な違いではありません。

本当に重要なのは、実際に手を動かして練習することです。そして、チャート上に表示されているものがどれほど複雑に見えても、その構造自体は非常にシンプルであることを理解することです。基本的には、インジケーターをどのように生成すべきかをコンパイラに静的に指示するだけです。静的なインジケーターの作成は簡単で、しかも楽しめる作業です。しかし、本当の面白さは動的インジケーターにあります。それについては、まもなく解説します。それまでの間、本記事で扱った内容を十分に学習し、実践してください。近いうちに、この実装手法をさらに刺激的で興味深いものへと発展させます。

MetaQuotes Ltdによりポルトガル語から翻訳されました。
元の記事: https://www.mql5.com/pt/articles/15828

添付されたファイル |
Anexo.zip (3.03 KB)
最後のコメント | ディスカッションに移動 (2)
Nguyen Tuấn Anh
Nguyen Tuấn Anh | 11 2月 2026 において 15:25
iBandをベースにカスタムインジケーターを作ろうとしています。
いろいろ検索した結果、ここに投稿することにしました。どなたか助けてくれるかもしれません。
これが完全なインジケーターです
//これはMQL5Indicatorsです。
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots   3

//--- プロット・ミドル
#property indicator_label1  "Middle"
#property indicator_type1   DRAW_LINE

//--- プロット・アッパー
#property indicator_label2  "Upper"
#property indicator_type2   DRAW_LINE

//--- プロット 下
#property indicator_label3  "Lower"
#property indicator_type3   DRAW_LINE

//==================================================
// 入力パラメータ
//==================================================
input int      InpBBPeriod      = 14;
input ENUM_APPLIED_PRICE inp_Applied_Price   = PRICE_MEDIAN;
input double   InpBBDeviation   = 2.0;
input int      InpBBShift       = 0;

input color    InpMiddleColor   = clrYellow;
input color    InpUpperColor    = clrYellow;
input color    InpLowerColor    = clrYellow;

input int      InpMiddleWidth   = 2;
input int      InpUpperWidth    = 2;
input int      InpLowerWidth    = 2;

input bool inp_BB_Show_Upper   = true;
input bool inp_BB_Show_Middle  = true;
input bool inp_BB_Show_Lower   = true;

input ENUM_LINE_STYLE InpMiddleStyle = STYLE_DOT;
input ENUM_LINE_STYLE InpUpperStyle  = STYLE_DOT;
input ENUM_LINE_STYLE InpLowerStyle  = STYLE_DOT;
//==================================================
#include <Anhnt/Configuration/NamingConfiguration.mqh>
//==================================================
// インジケータ・バッファ
//==================================================
double MiddleBuffer[];
double UpperBuffer[];
double LowerBuffer[];

//==================================================
// グローバル変数
//==================================================
int g_bb_handle = INVALID_HANDLE;

//https://www.mql5.com/ja/docs/indicators/ibands
//--- ボリンジャー・バンド・インディケータの値の数を保持する。

//+------------------------------------------------------------------+
int OnInit()
{
   //==================================================
   // バッファを設定する
   //==================================================
   SetIndexBuffer(BASE_LINE,  MiddleBuffer, INDICATOR_DATA);
   SetIndexBuffer(UPPER_BAND, UpperBuffer,  INDICATOR_DATA);
   SetIndexBuffer(LOWER_BAND, LowerBuffer,  INDICATOR_DATA);

   ArraySetAsSeries(MiddleBuffer, true);
   ArraySetAsSeries(UpperBuffer,  true);
   ArraySetAsSeries(LowerBuffer,  true);   

   //================================================== 
   // INPUT値をプロットに適用する(実行時に安全な方法)
   //==================================================
   PlotIndexSetInteger(BASE_LINE,  PLOT_LINE_COLOR, InpMiddleColor);
   PlotIndexSetInteger(UPPER_BAND, PLOT_LINE_COLOR, InpUpperColor);
   PlotIndexSetInteger(LOWER_BAND, PLOT_LINE_COLOR, InpLowerColor);

   PlotIndexSetInteger(BASE_LINE,  PLOT_LINE_STYLE, InpMiddleStyle);
   PlotIndexSetInteger(UPPER_BAND, PLOT_LINE_STYLE, InpUpperStyle);
   PlotIndexSetInteger(LOWER_BAND, PLOT_LINE_STYLE, InpLowerStyle);

   PlotIndexSetInteger(BASE_LINE,  PLOT_LINE_WIDTH, InpMiddleWidth);
   PlotIndexSetInteger(UPPER_BAND, PLOT_LINE_WIDTH, InpUpperWidth);
   PlotIndexSetInteger(LOWER_BAND, PLOT_LINE_WIDTH, InpLowerWidth);   

   PlotIndexSetInteger(
         BASE_LINE,
         PLOT_DRAW_TYPE,
         inp_BB_Show_Middle ? DRAW_LINE : DRAW_NONE
   );

   PlotIndexSetInteger(
         UPPER_BAND,
         PLOT_DRAW_TYPE,
         inp_BB_Show_Upper ? DRAW_LINE : DRAW_NONE
   );

   PlotIndexSetInteger(
         LOWER_BAND,
         PLOT_DRAW_TYPE,
         inp_BB_Show_Lower ? DRAW_LINE : DRAW_NONE
   );
   string name = SMT_PREFIX + SMT_BB_NAME +
                 "(" + (string)InpBBPeriod + "," +
                 DoubleToString(InpBBDeviation, 1) + ")";  
   
                                   
   IndicatorSetString(INDICATOR_SHORTNAME, name);
   //==================================================
   // iBands ハンドルの作成
   //==================================================
   g_bb_handle = iBands(
      _Symbol,
      _Period,
      InpBBPeriod,
      InpBBShift,
      InpBBDeviation,
      inp_Applied_Price
   );
   if(g_bb_handle == INVALID_HANDLE)
   {
      Print("iBand_Display INIT FAILED. Unable to create iBands handle. GetLastError = ", GetLastError());
      return INIT_FAILED;
   }
      
   Print("iBand_Display INIT SUCCESS");
   return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
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[]
)
{
   //https://www.mql5.com/ja/docs/indicators/ibands&amp;nbsp;  
   //--- iBandsの準備ができるまで待つ
   int calculated = BarsCalculated(g_bb_handle);
   if(calculated <= InpBBPeriod)
      return 0;   
      // Print("DEBUG from OnCalculate After Waiting BarsCalculated | Symbol=", _Symbol、
      // " | Period=", _Period、
      // " | BarsCalculated(iBands)=", calculated); 
   //--- このブロックは、インジケータが最初にチャートにアタッチされたときに実行されます。
   if(prev_calculated == 0)
   {
      ArrayInitialize(MiddleBuffer, EMPTY_VALUE);
      ArrayInitialize(UpperBuffer,  EMPTY_VALUE);
      ArrayInitialize(LowerBuffer,  EMPTY_VALUE);

      int to_copy = MathMin(calculated, rates_total);

      // 利用可能なすべてのデータを一度にコピーする
      CopyBuffer(g_bb_handle, BASE_LINE,  0, to_copy, MiddleBuffer);
      CopyBuffer(g_bb_handle, UPPER_BAND, 0, to_copy, UpperBuffer);
      CopyBuffer(g_bb_handle, LOWER_BAND, 0, to_copy, LowerBuffer);
      // Print("DEBUG from OnCalculate First Initial | Symbol=", _Symbol、
      // " | Period=", _Period、
      // " | BarsCalculated(iBands)=", calculated);
      return rates_total;    
   }   
   //--- このブロックは、新しいバーが開くたびに実行される。
   if(prev_calculated != rates_total && prev_calculated != 0)
   {
      //==================================================
   // NEXT RUNS:
   // 最新のバー (インデックス 0) のみを更新します。
   // 配列を手動でシフトしないでください(シリーズが処理します)。
   //==================================================
      double tmp[1];
      if(CopyBuffer(g_bb_handle, BASE_LINE, 0, 1, tmp) > 0)
      MiddleBuffer[0] = tmp[0];

      if(CopyBuffer(g_bb_handle, UPPER_BAND, 0, 1, tmp) > 0)
         UpperBuffer[0] = tmp[0];

      if(CopyBuffer(g_bb_handle, LOWER_BAND, 0, 1, tmp) > 0)
         LowerBuffer[0] = tmp[0];
      return rates_total;      
   }  
   return rates_total;
}
//+------------------------------------------------------------------+

bool FillArraysFromBuffers(
   double &base_values  [],   // ミドルバッファ
   double &upper_values [],   // アッパーバッファ
   double &lower_values [],   // ロワーバッファ
   int shift,                 // シフト = 0 → リアルタイム
   int ind_handle,
   int amount
)
{
   // 注意:
   // 現在は使用されていない。
   // 将来のヘルパー/EAロジックのために、予定通り保持する。

   ResetLastError();
   if(CopyBuffer(ind_handle, BASE_LINE,  -shift, amount, base_values) < 0)
      return false;
   if(CopyBuffer(ind_handle, UPPER_BAND, -shift, amount, upper_values) < 0)
      return false;
   if(CopyBuffer(ind_handle, LOWER_BAND, -shift, amount, lower_values) < 0)
      return false;
   return true;
}
BASE_LINE,UPPER_BAND,LOWER_BAND などの個々のラインの表示・ 非表示と、Custom Color のみを有効にしたいだけ です。
問題1は:
添付の画像でわかると思いますが、なぜチャートの下に緑があるのかわかりません。
CODE X
CODE X | 12 2月 2026 において 11:11
Nguyen Tuấn Anh # :
ありがとうございます。
iBandをベースとしたパーソナルなインジケーターを作ろうと思っています。
いろいろ調べた結果、ここに投稿することにしました。
これが完全版です。 非常にシンプルですが、ユーザが ベースライン、上バンド、下バンドといった 個別のラインを表示したり選択したりできるようにしたいだけです。
問題1は
添付の画像にあるように、画面上に緑色の領域があることがわかりません。
この緑の線は音量インジケーターです。これを無効にするには、チャートのプロパティを開き、ボリューム・インジケータをオフにする必要があります。または、ボリューム・カラーをCL_NONEに設定するだけで、緑色の線は消えます。
市場シミュレーション(第14回):ソケット(VIII) 市場シミュレーション(第14回):ソケット(VIII)
多くのプログラマは、Excelの使用をやめて、Pythonに直接移行し、PythonでExcelファイルを生成して後から結果を分析できるパッケージを使うべきだと考えるかもしれません。しかし、前回の記事で述べたように、この方法は多くのプログラマにとって最も簡単な解決策ではありますが、すべてのユーザーに受け入れられるわけではありません。そして、このような場合、常に正しいのはユーザーです。私たちプログラマは、すべてをうまく機能させる方法を見つけなければなりません。
ニューロボイド最適化アルゴリズム2 (NOA2) ニューロボイド最適化アルゴリズム2 (NOA2)
新しい独自最適化アルゴリズムNOA2 (Neuroboids Optimization Algorithm 2)は、群知能の原理とニューラルネットワークによる制御を組み合わせています。NOA2は、ニューラルボイド群の動作メカニズムに適応型ニューラルシステムを統合し、探索中にエージェント自身が行動を自己修正できるよう設計されています。現在も開発中のアルゴリズムですが、複雑な最適化問題の解決に有望な結果を示しています。
カオス理論アプローチによる買われ過ぎと売られ過ぎのトレンド分析 カオス理論アプローチによる買われ過ぎと売られ過ぎのトレンド分析
市場の買われすぎや売られすぎの状態を、カオス理論に基づいて評価します。この手法では、カオス理論、フラクタル幾何学、ニューラルネットワークの原理を統合し、金融市場の予測をおこないます。この研究では、市場のランダム性の尺度として、また売買シグナルの動的適応として、リアプノフ指数を使用する方法を実証しています。市場のランダム性の評価にはリアプノフ指数を用い、売買シグナルの動的適応を実現しています。具体的には、フラクタルノイズ生成アルゴリズム、双曲線正接関数による活性化、モーメント最適化を組み合わせた手法を採用しています。
FXにおけるスワップ差裁定:合成ポートフォリオの構築と一貫したスワップフローの生成 FXにおけるスワップ差裁定:合成ポートフォリオの構築と一貫したスワップフローの生成
金利差を活用して利益を得る方法をご存じでしょうか。本記事では、FXにおけるスワップ差裁定(スワップアービトラージ)を活用し、毎晩安定した利益を生み出し、市場の変動に強いポートフォリオを構築する方法について解説します。