前回はカスタムインジケ-タについて解説しました。
まず、「そもそもカスタムインジケ-タとは何か?」という基本から説明を行いました。
※詳細は「カスタムインジケ-タとは?→MT5に標準実装されていない特別仕様のインジケータのこと。」セクションをご覧ください。
その具体例として、MT5に実装されているカスタムインジケ-タ「BB」を取り上げ、そのサンプルコードを見ながら、要所要所のコード記述と、重要な役割を果たす関数(SetIndexBuffer関数とPlotIndexSetString関数)についての説明を行いました。
また、カスタムインジケ-タの情報をEAに実装するのにあたり、カスタムインジケ-タで使われているバッファ数や、描画バッファとインデックス番号の紐づけ状況を把握する事の必要性について解説し、その確認方法についてもお話しました。
※詳しくは前回の記事内、
「MT5のデータウィンドウから、カスタムインジケ-タのバッファ数を確認する」セクション
及び
「カスタムインジケ-タの描画バッファのインデックス番号を推測する」セクション
をご覧ください。
今回は、前回解説したカスタムインジケ-タをEAに有効活用する為の1手段として、iCustom関数の使い方についてお話していきたいと思います。
iCustom関数はかなり特殊な関数ですので、利用にあたって押さえておかなくてはいけない注意点がいくつかあります。
ただ、iCustom関数を自由に使いこなせるようになれば、MT5に実装済みの組み込みインジケータだけではなく、インターネット上で共有されていたり、購入できるカスタムインジケ-タもEAに実装できるようになり、より一層EA開発の可能性を押し広げる事ができるようになります。
iCustom関数の使い方から注意点まで漏れなく伝えていきたいと思いますので、是非今回も楽しんで学習して頂ければと思います。
iCustom関数とは?
iCustom関数は、カスタムインジケ-タの値を特定して、その値を取得する為に使われる関数です。
この講座の中ではiMA関数やiStochastic関数のように、MT5内に実装されているインジケータ(=組み込みインジケータ)の値を取得する為の関数をいくつか紹介してきました。
しかし、インジケータというのは、MT5に実装されているもの以外にもたくさんあり、それらMT5に標準実装されていないインジケータを総称してカスタムインジケ-タと呼ぶ、という事は前回解説いたしました。
iCustom関数は、カスタムインジケ-タをMT5のチャートに表示させるだけではなく、その値を自作EAに利用したい時に使われる関数となります。
iCustom関数の引数と戻り値について
iCustom関数の引数と戻り値は以下のようになっています。
int iCustom(
string symbol, // 銘柄名
ENUM_TIMEFRAMES period, // 期間
string name // フォルダ/カスタム指標名
... // 指標入力パラメータのリスト
);//戻り値は指標ハンドル
第1引数「symbol」には取引銘柄名を設定する。
iCustom関数の第1引数「symbol」には取引銘柄名を設定します。
定義済み変数「_Symbol」を記述すると、プログラムを挿入したチャートの銘柄を指定したことになります。
※定義済み変数については↓の記事をご参照ください。
第2引数「period」には時間軸を設定する。
iCustom関数の第2引数「period」には時間軸を指定します。定数値ENUM_TIMEFRAMESで定められた値を設定します。0、もしくはPERIOD_CURRENTと記述すると現在のチャートの時間軸が適用されます
第3引数「name」にはカスタムインジケータの名前を正確に設定する。
iCustom関数の第3引数「name」にはカスタムインジケ-タの名前を「正確に」設定します。
この「正確に」という所が重要で、「正確に」という要件を満たせずに、iCustom関数を使ったEAが正常に作動しない、というケースは非常に多いので重ねて注意をお願いします。
改めてですが、第3引数には拡張子を除いた、カスタムインジケ-タの名前を「正確に」記述する必要があります。
「正確に」記述する為には、主に以下の点に注意を払わなければなりません。
・インジケータ名の大文字小文字の区別が一致しているかどうか
前回の講座記事で解説したカスタムインジケ-タ「BB」を例にすれば・・・↓
int cutomHandle=iCustom(_Symbol,PERIOD_CURRENT,"bb");
//↑正確なインジケータ名は「BB」なので、正しく値が読み込めない
“bb”と表記しても、正確なインジケータ名は「BB」なので、プログラムを実行した際に正しく値を読み込む事ができません。
・スペースなどが意図せず入っていないかどうか
↑これも前回の講座記事で解説したカスタムインジケ-タ「BB」を例にすれば・・・↓
int cutomHandle=iCustom(_Symbol,PERIOD_CURRENT,"BB ");
//↑正確なインジケータ名は「BB」なので、正しく値が読み込めない
正確なインジケータ名は「BB」なのに、半角スペースが一個入った「BB 」という記述になってしまっているので、プログラムを実行した際に正しく値を読み込む事ができません。
※逆のパターンで、実際にはスペースが入っている正式名称なのに、スペースを省略してしまっている為に、正しく値を読み込むことができない、という事もあるので注意が必要です。
・フォルダー構造まで踏まえ、正確に記述されているかどうか
↑これについてはもう少し説明が必要になります。
大前提として、iCustom関数に使うカスタムインジケ-タの実行ファイルは「MQL5フォルダ」ディレクトリ内にある「Indicator」サブフォルダに格納されている必要があります。
そしてもし、「Indicator」サブフォルダのさらに下の階層にあるサブフォルダに格納されている場合、そのサブフォルダ名も把握している必要があります。
例えば前回111回でも取り上げた「BB」カスタムインジケ-タのファイルは、「Examples」というサブフォルダに格納されています。
この場合、iCustom関数の第3引数には”Examples//BB”という記述をする必要があります。
つまり↓のような記述は駄目で・・・
int cutomHandle=iCustom(_Symbol,PERIOD_CURRENT,"BB");
↓のような記述に改める必要があります。
int cutomHandle=iCustom(_Symbol,PERIOD_CURRENT,"Examples//BB");
↑のように、カスタムインジケ-タ名の前に、ダブルスラッシュ(//)を書き、サブフォルダ名「Examples」を記述する必要があります。
インジケータファイルが「Indicator」サブフォルダのさらに下の階層にあるサブフォルダに格納されているにも関わらず、第3引数にサブフォルダ名を含めずインジケータ名だけを記載した場合、プログラムを実行した際に読み込みエラーが発生します(コンパイルエラーは発生しません)
以下のようなソースコードを実行した場合、
void OnTick()
{
double middle[],upper[],lower[];
ArraySetAsSeries(middle,true);
ArraySetAsSeries(upper,true);
ArraySetAsSeries(lower,true);
int cutomHandle=iCustom(_Symbol,PERIOD_CURRENT,"BB");
//↑インジケータ名の表記が間違っている為読み込みエラーが発生する
CopyBuffer(cutomHandle,0,0,10,middle);
CopyBuffer(cutomHandle,1,0,10,upper);
CopyBuffer(cutomHandle,2,0,10,lower);
Print(middle[1]);
Print(upper[1]);
Print(lower[1]);
}
下の画像のように
「cannot load custom indicator’BB'[4802]」というエラーが発生します。
「インジケータ名’BB’を読み込むことができませんでした」という意味合いのエラーです。
iCustom関数の第3引数を以下のように変更した上で再度実行してみると・・・
int cutomHandle=iCustom(_Symbol,PERIOD_CURRENT,"Examples//BB");
//第3引数を"Examples//BB"に修正する
↓きちんと、値を読み込み、ログ出力されるようになりました。
第4引数以降にはカスタムインジケータに設定されているinput変数に従った情報を順番通りに設定する。
この第4引数以降には、使おうとしているカスタムインジケ-タにあらかじめ設定されているinput変数に従った情報を順番通りに記述する必要があります。
「カスタムインジケ-タにあらかじめ設定されているinput変数に従った情報」
とはどういうことか?というのをまずは説明します。
前回から例として取り上げているカスタムインジケ-タ「BB」は、 int型の「InpBandsPeriod」、
同じくint型の「InpBandsShift」、double型の 「InpBandsDeviations」という3つのinput変数が設定されています↓
従って、iCustom関数の第4引数から第6引数までを、int型、int型、double型の順番で記述する必要があります。
int cutomHandle=iCustom(_Symbol,PERIOD_CURRENT,"BB",15,0,3.0);
↑のような形ですね。ただ、これでは汎用性に欠けますから、メインプログラムでもinput変数を定めてパラメータとして変更できるようにするのが望ましいです。
input int InpBandsPeriod_Main=20; // メインプログラム用期間設定
input int InpBandsShift_Main=0; //メインプログラム用シフト設定
input double InpBandsDeviations_Main=2.0; //メインプログラム用標準偏差設定
void OnTick()
{
double middle[],upper[],lower[];
ArraySetAsSeries(middle,true);
ArraySetAsSeries(upper,true);
ArraySetAsSeries(lower,true);
int cutomHandle=iCustom(_Symbol,
PERIOD_CURRENT,
"Examples//BB",
InpBandsPeriod_Main,
InpBandsShift_Main,
InpBandsDeviations_Main);
CopyBuffer(cutomHandle,0,0,10,middle);
CopyBuffer(cutomHandle,1,0,10,upper);
CopyBuffer(cutomHandle,2,0,10,lower);
Print(middle[1]);
Print(upper[1]);
Print(lower[1]);
}
//+------------------------------------------------------------------+
↑メインプログラムのグローバル領域でint型の「InpBandsPeriod_Main」、
同じくint型の「InpBandsShift_Main」、double型の 「InpBandsDeviations_Main」という3つのinput変数を設定しました。
カスタムインジケ-タ「BB」のinput変数設定に忠実に合わせた形です。
※input変数については↓の記事をご参照ください。
※int型については↓の記事をご参照ください。
※double型については↓の記事をご参照ください。
カスタムインジケ-タ「BB」の場合は、以上のような手順で記述すればよい訳ですが、やっかいなのは、カスタムインジケ-タごとに用意されているinput変数の数が異なるという事です。
input変数が1個のカスタムインジケ-タの場合は第4引数だけ設定すればいい訳ですが、5個あるカスタムインジケ-タの場合は第4引数から第8引数まで設定する必要があります。
ただ数を合わせれば良いだけでなくデータ型も正しく設定しなくてはいけません。
↓の動画は本来、第6引数にはdouble型のデータを設定しなくてはいけない所を、途中で文字列の”2.5″(=string型)に変更したのち、ファイルを実行している模様です。
double型のデータであるべき所をstring型データが設定されている為、これも「cannot load custom indicator’BB'[4802]」という読込エラーが発生しています。
※データ型については↓の記事をご参照ください。
このように、元のカスタムインジケ-タに設定されているinput変数のデータ型と違う記述をしてしまうと、正常に動作しない可能性がありますし、input変数の数と異なる記述をしてしまっても同様に正常作動しない可能性があります。
「可能性がある」という曖昧な表現をしたのは、元のカスタムインジケ-タに設定されているinput変数のデータ型と違う記述を下からといって、必ずエラーが発生する訳ではないからです。
先ほど例に挙げたdouble型のデータであるべき所をstring型データに設定したケースは、数値であるべき所を文字列にしてしまっているわけですから、読み込みエラーが発生するのは容易に想像できるかと思います。
これが例えば、double型であるところをint型に記述した場合などは、同じ数値である訳ですから、読み込みエラーは発生しない可能性が高いです。
ただ、本来double型であるところをint型に記述した場合、データの切り詰め(truncation)が発生し、正確なデータの読み込みを阻害する場合があります。
※データの切り詰め等に関しては↓の記事をご参照ください。
従って、原則的には元のカスタムインジケ-タに設定されているinput変数のデータ型は揃えるようにするべきでしょう。
第4引数以降のinput変数記述は省略可能
第4引数以降のinput変数記述を一切記述せずに、省略するという事は可能です。その場合、元々のカスタムインジケ-タに設定されている初期値が適用されます。
この記事内の『第3引数「name」にはカスタムインジケータの名前を正確に設定する』セクションで例に出したサンプルコードでも第1引数~第3引数までの入力しかしていませんでした。
しかし第3引数のカスタムインジケ-タ名を正しく入力した後は、正常に値を習得できています。
これは第4引数以降の入力を省略した事によって、第4引数以降の値には初期値が設定されたことを意味増します。実際に記述されているのは↓なのですが・・・
int cutomHandle=iCustom(_Symbol,PERIOD_CURRENT,"Examples//BB");
カスタムインジケ-タ「BB」には3つinput変数が用意されており、以下の初期値が設定されているので・・・↓
↓のような書かれ方をしているのと同じことになっています。
int cutomHandle=iCustom(_Symbol,
PERIOD_CURRENT,
"Examples//BB",
20,//InpBandsPeriodの初期値「20」が設定される
0,//InpBandsShiftの初期値「0」が設定される
2.0);//InpBandsDeviationsの初期値「2.0」が設定される
input変数箇所は全て省略しても構いませんし、
・MQL5 EA講座 第46回「関数の初期値について」に記載されている原則に違反していなければ、一部の引数だけ省略することも可能です。
「BB」インジケータを例にした場合、
input変数の数とデータ型を完全に合わせて記述する場合のサンプルコードは以下のようになります。
input int InpBandsPeriod_Main=20; // メインプログラム用期間設定
input int InpBandsShift_Main=0; //メインプログラム用シフト設定
input double InpBandsDeviations_Main=2.0; //メインプログラム用標準偏差設定
void OnTick()
{
int cutomHandle=iCustom(_Symbol,
PERIOD_CURRENT,
"Examples//BB",
InpBandsPeriod_Main,
InpBandsShift_Main,
InpBandsDeviations_Main,
);
//input変数の数とデータ型を完全に合わせて記述する場合
↑カスタムインジケ-タ「BB」のファイルに設定されている3つのinput変数名に「_Main」という接尾辞をつけた「InpBandsPeriod_Main」「InpBandsShift_Main」「InpBandsDeviations_Main」というinput変数をグローバル領域に作り、それをiCustom関数の第4引数~第6引数に記述しました。
一方、input変数箇所は全て省略した場合のサンプルコードは以下のようになります↓
int cutomHandle=iCustom(_Symbol,PERIOD_CURRENT,"Examples//BB");
//input変数箇所は全て省略した場合
一部の引数だけ省略する、例えば第3引数だけ省略する場合ののサンプルコードは以下のようになります。
int cutomHandle=iCustom(_Symbol,
PERIOD_CURRENT,
"Examples//BB",
InpBandsPeriod_Main,
InpBandsShift_Main);
//第3引数だけ省略した場合
iCustom関数を使ってカスタムインジケータの値を取得する具体的な手順
iCustom関数の戻り値及び、引数に関する説明が終わったので、
次は、iCustom関数を使ってカスタムインジケ-タの値を取得する具体的な手順を説明します。
とはいっても、カスタムインジケ-タもインジケータの1種なので、↓の記事
・MQL5 EA講座 第108回「インジケータを使ってエントリーシグナルを生成する」
で解説した、インジケータ値取得の手順と、殆ど同じです。
iCustom関数の第4引数に記述するための値をinput変数で設定する
既に書いたように、iCustom関数の第4引数以降には、「使おうとしているカスタムインジケ-タに設定されているinput変数に従った情報」を順番通りに記述する必要があります。
従って、メインプログラムのグローバル領域に必要なinput変数を設定しておきます。
カスタムインジケ-タ「BB」は、3つのinput変数が用意されていますから、メインプログラムにも3つinput変数を設定します↓
input int InpBandsPeriod_Main=20; // メインプログラム用期間設定
input int InpBandsShift_Main=0; //メインプログラム用シフト設定
input double InpBandsDeviations_Main=2.0; //メインプログラム用標準偏差設定
インジケータの値を格納する配列の宣言
OnTick関数の中に、カスタムインジケ-タの値を格納する配列の宣言を行います。
double middle[],upper[],lower[];
「BB」はマルチバッファインジケータなので、今回はmiddle[],upper[],lower[]という3つの配列を用意しましたが、もしEAのロジックに必要がないのであれば必ずしも3つ配列をしなくても大丈夫です。
例えば、中央ライン(=移動平均線)の値はEAロジックに採用しない、という事であればmiddle[]は省いてしまって構いません。
iCustom関数によるハンドルの取得
iCustom関数の戻り値は、カスタムインジケ-タのハンドル値です。組み込みインジケータの関数と同様、値そのものを返してくれるわけではありません。最終的にCopyBuffer関数を使って配列にコピーをする為に、まずはハンドル値を獲得します。
int cutomHandle=iCustom(_Symbol,
PERIOD_CURRENT,
"Examples//BB",
InpBandsPeriod_Main,
InpBandsShift_Main,
InpBandsDeviations_Main,
);
配列を時系列にセットする
続いて用意した配列の時系列セットを行います。
配列の時系列セットにはArraySetAsSeries関数を使います。
ArraySetAsSeries(middle,true);
ArraySetAsSeries(upper,true);
ArraySetAsSeries(lower,true);
※ArraySetAsSeries関数については↓の記事をご参照ください。
CopyBuffer関数による、インジケータの値情報を配列にコピー
最後にCopyBuffer関数によってカスタムインジケ-タの値情報を配列にコピーします。
CopyBuffer(cutomHandle,0,0,10,middle);
CopyBuffer(cutomHandle,1,0,10,upper);
CopyBuffer(cutomHandle,2,0,10,lower);
一連の流れを見てもらえば、改めて他の組み込みインジケータ用関数と使い方は同じであることがご理解いただけたかと思います。
引数の設定で、いくつか注意点を書いてきましたが、その点さえ押さえておけば、iCustom関数を怖がる必要は全くありません。
改めて注意を払いたい点は、自分が使いたいカスタムインジケ-タの値が、何番のバッファ番号かという事を正確に把握している必要があるという事です。
特に使いたいカスタムインジケ-タがマルチバッファインジケータの場合、使いたい値とは違う値を用いてしまう可能性をはらんでいます。
バッファ番号の確認手順等については改めて前回の記事↓を読んで頂くことをお勧めします。
まとめ
今回はiCustom関数について解説を行いました。
iCustom関数は、カスタムインジケ-タの値を特定して、その値を取得する為に使われる関数である、という前提をまずお伝えした上で、iCustom関数の引数と戻り値について解説しました。
iCustom関数を使うにあたり、特に注意を払いたいのが
第3引数に、カスタムインジケ-タの名前を「正確に」記述する必要がある点と、
第4引数以降には「使おうとしているカスタムインジケ-タに設定されているinput変数に従った情報」を順番通りに記述する必要がある点
です。
この部分に記述ミスがあると、カスタムインジケ-タの値読み込みが正しく行われない可能性があるので、注意しましょう。
今回の記事における、
『第3引数「name」にはカスタムインジケータの名前を正確に設定する。』セクション
及び
『第4引数以降にはカスタムインジケータに設定されているinput変数に従った情報を順番通りに設定する。』セクションを繰り返し確認して頂ければと思います。
最後に、iCustom関数をメインプログラムでどのように使っていくのか、という点について説明をしました。基本的には他の組み込みインジケータ用の関数と同じように、
↓
値を格納する配列を用意
ArraySetAsSeries関数を使って配列を時系列セット
↓
CopyBuffer関数を使って、値を配列にコピー
という手順を踏みます。
詳しくは
今回の記事『iCustom関数を使ってカスタムインジケータの値を取得する具体的な手順』セクションをご覧ください。
今回は元々MT5に実装されていた「BB」というカスタムインジケ-タを例にして説明しましたが、今回説明したiCustom関数を使った工程を踏めば、どのようなカスタムインジケ-タもEAロジックに組み込む事ができます。
ただし、iCustom関数はシステムトレードの可能性を押し広げるポテンシャルを秘めた関数である一方で、確実な利益をもたらす魔法の杖では決してありません。
また、今回の記事でも書いてきたように、iCustom関数にはいくつかの注意点があり、それを押さえた利用をしないと正しく作用しないことが多々あります。今回の記事をしっかりと理解し、EA開発にうまく利用できるようになりましょう。
※ネット上にあまた存在するカスタムインジケ-タをiCustom関数に突っ込んで、「動かなかった」という問い合わせを頂いても、お答えしかねますのであらかじめご了承ください。
今回は以上とさせていただきます。
最後までお読みいただきありがとうございました。
MQL5 EA講座 第111回「カスタムインジケ-タについての基本を知る」←
→MQL5 EA講座 第113回「インジケータの値をトレードシグナルに使う方法」
※インジケータのコード記述について理解を深めるのであれば、以下の記事もおススメです。
パラボリックSARを例にとり、インジケータのコード記述を一気通貫で、徹底解説していますので、インジケータだけではなく、今までの講座記事で学んできたことを網羅的に復習できる絶好の機会にもなります↓