前回は、インジケータの値取得を簡略化できるクラスを作る解説の第1回目でした。
MT5に組み込まれているインジケータ共通の処理を担う基礎クラスと、
各インジケータごとに異なった処理が必要な工程を担う、派生クラス
を作っていくというロードマップを示し、前回はまず基礎クラス(=CBaseIndicatorクラス)を作成しました。
※詳細は前回の記事の「インジケ-タクラス作成のロードマップ」セクションをご覧ください。
前回作成した基礎クラスであるCBaseIndicatorクラスには以下のメンバを追加しました。
・メンバ変数「handle」→インジケータのハンドル値を格納する、アクセスレベル=protectedの変数
・メンバ変数配列「main」→インジケータ値を格納する、アクセスレベル=protectedの配列
・CBaseIndicator関数→インスタンス生成時に、配列の時系列をセットする、アクセスレベル=publicのコンストラクタ
・メンバ関数「Main」→インジケータの値を取得して戻り値として返す、アクセスレベル=publicのメンバ関数。
・メンバ関数「Release」→インジケータの値をメモリから解放する時に使う、アクセスレベル=publicのメンバ関数。
・メンバ関数「Init」→戻り値だけを定めた、アクセスレベル=publicの仮想関数。細かい処理内容は、各派生クラスで定義する。
—————————————————————-
今回は、前回作った基礎クラス(=CBaseIndicatorクラス)を元にして、今後、どんなインジケータを使おうとしても滞りなく値を取得出来るようにするための派生クラスを作っていきます。
- CBaseIndicatorクラスの派生クラスを作る
CBaseIndicatorクラスの派生クラスを作る
しつこいかもしれませんが、大事な点なので前提をおさらいしておきましょう。
前回作ったCBaseIndicatorクラスは、これから作る各インジケータ用の派生クラスの親クラスとなるものです。この親クラスではどのインジケータにも共通する処理を担ってもらいます。
しかしその一方で、インジケータにはたくさんの種類があり、その値取得にはインジケータごとに違うプロセスも踏まなくてはいけません。
そこで、自分が使いたいと思うインジケータ用の派生クラスを別途作っていこう、というのが今回の記事の趣旨となります。
その手始めとして、まずは移動平均線の派生クラスから作っていきましょう。
※移動平均線自体の詳しい解説は↓の記事で行っていますので、宜しければご覧ください。
移動平均線の派生クラスを作る
移動平均線は、シングルバッファインジケータです。
※シングルバッファインジケータというのは、バッファの数=「インジケータとしてMT5のチャートに表示する数値の数」が1つだけのインジケータの事です。
従って、派生クラスを作る手間も、後で解説するマルチバッファインジケータよりは少ないです。
class CDerivediMA : public CBaseIndicator
{
};
派生クラス名は「CDerivediMA」クラスとしました。
classキーワード
↓
クラス名「「CDerivediMA」の後にコロン(:)、
↓
↓
親クラス名である「CBaseIndicator」
の順番で記述する事によって、「CDerivediMA」クラスがCBaseIndicatorクラスの派生クラスであるという意味合いになります。
※派生クラスについては↓の記事をご参照ください。
・MQL5 EA講座 第51回「クラスについて4 -派生クラス-」
※private,protected,publicなどのアクセス指定子については以下の記事をご参照ください。
・MQL5 EA講座 第50回「クラスについて3 -アクセス指定子-」
この「CDerivediMA」クラスの中にメンバを追加していくのですが、今回追加するメンバは1つだけです。
class CDerivediMA : public CBaseIndicator
{
public:
int Init(string parSymbol,ENUM_TIMEFRAMES parTimeframe,int parMAPeriod,int parMAShift,ENUM_MA_METHOD parMAMethod,ENUM_APPLIED_PRICE parMAPrice);
};
アクセスレベル=publicの領域にメンバ関数「Init」を追加しました。
注意して頂きたいのが、追加するメンバは「Init」1つだけですが、「CDerivediMA」クラスはCBaseIndicatorクラスの派生クラスなので、実際には以下のCBaseIndicatorクラス所属メンバも使えるという事です。
【使えるCBaseIndicatorクラス所属のメンバ一覧】
・「handle」 (インジケータのハンドル値を格納する変数)
・CBaseIndicator関数 (インスタンス生成時に、配列の時系列をセットするコンストラクタ)
・Main関数 (インジケータの値を取得して戻り値として返すメンバ関数)
・Release関数(インジケータの値をメモリから解放する時に使メンバ関数)
イメージとしては↓のような感じです。
class CDerivediMA : public CBaseIndicator
{
//protected:
// int handle;//書かれてないけど実際は使える
// double main[];//書かれてないけど実際は使える
//public:
//CBaseIndicator(void);書かれてないけど実際は使える
//double Main(int parIndex=0);//書かれてないけど実際は使える
//void Release();//書かれてないけど実際は使える
public:
int Init(string parSymbol,ENUM_TIMEFRAMES parTimeframe,int parMAPeriod,int parMAShift,ENUM_MA_METHOD parMAMethod,ENUM_APPLIED_PRICE parMAPrice);
};
以上の前提を押さえた上で改めて、「CDerivediMA」クラスの中身を順を追って見てきましょう。
仮想関数「Init」の仮引数と処理実装記述をCDerivediMAクラスで再定義する
追加メンバの「Init」は親クラス「CBaseIndicator」で定義した仮想関数です。
※詳細は前回講座記事の『メンバ関数「Init」は戻り値だけを定めた仮想関数』セクションをご覧ください。
親クラス「CBaseIndicator」の時には、戻り値のデータ型がint型であるという事と、、return演算子で戻す値がアクセスレベル=protectedのメンバ変数「handle」、ということだけでした。
※仮想関数については↓の記事をご参照ください。
・MQL5 EA講座 第53回「クラスについて6 -仮想関数-」
従って、派生クラスである「CDerivediMA」で、改めて仮引数と処理実装記述を設定します。
※メンバ変数「handle」については、前回記事の『メンバ変数「handle」はインジケ-タのハンドル値を格納する』セクションをご覧ください。
CDerivediMAクラスにおける仮想関数「Init」の仮引数について
「CDerivediMA」クラスにおける、仮想関数「Init」の仮引数は以下のようになっています。
(string parSymbol,//銘柄名を指定
ENUM_TIMEFRAMES parTimeframe,//チャート時間軸を指定
int parMAPeriod,//移動平均を計算する期間を指定
int parMAShift,//計算した移動平均の値をどれくらいずらして表示するかを指定
ENUM_MA_METHOD parMAMethod,//移動平均平滑化の種類を指定
ENUM_APPLIED_PRICE parMAPrice//適用価格の種類を指定)
仮引数は、移動平均線の値を取得する為に使う、iMA関数の各引数に記述される想定ですので、iMA関数の各引数に完全対応した形になっています。
※iMA関数の各引数については、コチラのリンクをご参照ください。
<参照>
・ENUM_TIMEFRAMES/ENUM_MA_METHOD/ENUM_APPLIED_PRICE
CDerivediMAクラスにおける仮想関数Initの処理実装記述について
仮想関数 「Init」の処理実装記述については以下のようになっています。
int CDerivediMA::Init(string parSymbol,ENUM_TIMEFRAMES parTimeframe,int parMAPeriod,int parMAShift,ENUM_MA_METHOD parMAMethod,ENUM_APPLIED_PRICE parMAPrice)
{
handle = iMA(parSymbol,parTimeframe,parMAPeriod,parMAShift,parMAMethod,parMAPrice);
return(handle);
}
{}内の処理実装記述では、iMA関数を呼び出して、親クラスであるCBaseIndicatorクラスのメメンバ変数「handle」に、取得したハンドル値を格納しています。
※メンバ変数「handle」のアクセスレベルはCBaseIndicatorクラス内でprotectedに設定されていますので、派生クラスである「CDerivediMA」クラスのメンバ関数からはアクセスができます。
あとは実際にEAを自作するメインプログラムにおいて、今回処理実装記述を施した
「Init」関数(「CDerivediMA」クラスのメンバ)
と
メンバ関数「Main」(CBaseIndicatorクラスのメンバ)を呼び出すことによって、移動平均線の値を簡単に取得する事ができます。
実際にメインプログラムでCDerivediMAクラスを使い、移動平均の値を取得してみる。
では実際に、EAを自作する事を想定してメインプログラム内で「CDerivediMA」クラスを使い、移動平均線の値を取得する記述をしてみましょう。
//+------------------------------------------------------------------+
//| CDerivediMAClassExample.mq5 |
//| MQL5ssei |
//| https://mqlinvestmentlab.com/ |
//+------------------------------------------------------------------+
#property copyright "MQL5ssei"
#property link "https://mqlinvestmentlab.com/"
#property version "1.00"
//OriginalIndicators.mqhファイルのインクルード
#include <OriginalIndicators.mqh>
//CDerivediMAクラスのインスタンスを宣言
CDerivediMA MA;
//必要なパラメータ
input int MAPeriod=20;//移動平均の期間
input int MAShift=0;//移動平均をどのくらいずらすか
input ENUM_MA_METHOD MAMethod=MODE_SMA;//移動平均の種類
input ENUM_APPLIED_PRICE AppliedPrice=PRICE_CLOSE;//移動平均に適用する価格種類
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{ //Init関数を呼び出して移動平均のハンドル値を取得
MA.Init(_Symbol,_Period,MAPeriod,MAShift,MAMethod,AppliedPrice);
return(INIT_SUCCEEDED);
}
void OnTick()
{ //現在足の移動平均値を取得する
double currentMA=MA.Main();
}
//+------------------------------------------------------------------+
OriginalIndicators.mqhファイルのインクルードする
まずは「OriginalIndicators.mqh」ファイルをメインプログラムのグローバル領域(関数の外の領域)にインクルードします。
//OriginalIndicators.mqhファイルのインクルード
#include <OriginalIndicators.mqh>
※インクルードファイルについては下記の記事をご参照ください。
MQL5 EA講座 第56回「#include命令(#include directive)」
CDerivediMAクラスのインスタンスを宣言する
include命令により、晴れて「CDerivediMA」クラスが使えるようになったので、次はインスタンスを宣言します。
//CDerivediMAクラスのインスタンスを宣言
CDerivediMA MA;
インスタンス名は「MA」としました。
※インスタンスについては下記の記事をご参照ください。
各種input変数を宣言する
インスタンスを宣言した後は、各種input変数を宣言します。
//必要なパラメータ
input int MAPeriod=20;//移動平均の期間
input int MAShift=0;//移動平均をどのくらいずらすか
input ENUM_MA_METHOD MAMethod=MODE_SMA;//移動平均の種類
input ENUM_APPLIED_PRICE AppliedPrice=PRICE_CLOSE;//移動平均に適用する価格種類
この部分は講座記事第108回の「インジケータ関数の引数に記述するための値をinput変数で設定する」セクション(移動平均線編)と全く同じです。
※input変数については下記の記事をご参照ください↓
OnInit関数内にCDerivediMAクラスのInit関数を呼び出す
次にやる事はOnInit関数内に「CDerivediMA」クラスの「Init」関数を呼び出す事です。
int OnInit()
{ //Init関数を呼び出して移動平均のハンドル値を取得
MA.Init(_Symbol,_Period,MAPeriod,MAShift,MAMethod,AppliedPrice);
return(INIT_SUCCEEDED);
}
「CDerivediMA」クラスの「Init」関数は、iMA関数を使って移動平均線のハンドル値を呼び出す機能を担っています。
ハンドル値の取得という作業は、1度だけ行えば事足りるので,EAをMT5チャートに挿入する時にだけ処理を行うOnInit関数 内で呼び出すのが妥当でしょう(OnTick関数内で呼び出しても特に差しさわりはありませんが、何度も呼び出す必要のない処理です)
※OnInit関数については↓の記事をご参照ください。
OnTick関数内でCDerivediMAクラスのメンバ関数「Main」を呼び出す
最後にOnTick関数内で「CDerivediMA」クラスのメンバ関数「Main」を呼び出します。
void OnTick()
{ //現在足の移動平均値を取得する
double currentMA=MA.Main();
Print("移動平均価格= ",currentMA);
}
double型の変数「currentMA」を宣言し、そこに「CDerivediMA」クラスのメンバ関数「Main」を呼び出して戻り値を代入します。メンバ関数「Main」の引数はインデックス(通し番号)を指定するようになっています。
初期値は「0」に設定されていますので、()内に何も記述しなければ自動的にインデックス「0」、すなわち現在足の移動平均情報が取得できる、という訳です。
※初期値については下記の記事をご参照ください。
Print関数で取得した値をログ出力している挙動は以下のようになっています。
「CDerivediMA」クラスを利用した移動平均値の取得手順は以上になります。
ストキャスティクスの派生クラスを作る
もう1つのインジケータ用派生クラスの例として、今度はストキャスティクスの派生クラスを作っていきたいと思います。
ストキャスティクスはマルチバッファインジケータとなります。
マルチバッファインジケータは、バッファの数が複数=「MT5のチャートに表示する数値の数」が複数のインジケータの事を指します
派生クラスの作成過程では、シングルバッファインジケータとはいくつか異なる点もあります。
違いに注意を払いながら見てきましょう。
class CDerivediStochastic : public CBaseIndicator
{
};
まずはクラス名の宣言です。クラス名を「CDerivediStochastic」としました。
classキーワード
↓
クラス名「CDerivediStochastic」の後にコロン(:)、
↓
↓
親クラス名である「CBaseIndicator」
の順番で記述する事によって、「CDerivediStochastic」クラスがCBaseIndicatorクラスの派生クラスであるという意味合いになります。
この中に追加するメンバは以下のようになります。
class CDerivediStochastic : public CBaseIndicator
{
private:
double signal[];
public:
int Init(string parSymbol, ENUM_TIMEFRAMES parTimeframe, int parKPeriod, int parDPeriod, int parSlowing, ENUM_MA_METHOD parMAMethod, ENUM_STO_PRICE parPrice);
double Signal(int parShift=0);
CDerivediStochastic(void);
};
{}内に追加したメンバは上記の通りですが、「CDerivediStochastic」クラスは派生クラスなので、親クラスであるCBaseIndicatorクラスのメンバも使えます。実際のイメージとしては以下のようになるでしょうか?
class CDerivediStochastic : public CBaseIndicator
{
private:
double signal[];
protected:
int handle;//書かれてないけど実際は使える
double main[];//書かれてないけど実際は使える
public:
int Init(string parSymbol, ENUM_TIMEFRAMES parTimeframe, int parKPeriod, int parDPeriod, int parSlowing, ENUM_MA_METHOD parMAMethod, ENUM_STO_PRICE parPrice);
double Signal(int parShift=0);
CDerivediStochastic(void);
CBaseIndicator(void);//書かれてないけど実際は使える
double Main(int parIndex=0);//書かれてないけど実際は使える
void Release();//書かれてないけど実際は使える
};
移動平均線の値を取得する「CDerivediMA」クラスの時は、{}内に追加したメンバは仮想関数である「Init」関数のみだったのですが、ストキャスティクスの値取得を目的としている「CDerivediStochastic」クラスでは
アクセスレベル₌publicにSignal関数とCDerivediStochastic関数という
3つのメンバを追加しました。
「CDerivediMA」クラスと比べ、なぜこのような違いが生じるか?ですが、ストキャスティクスがマルチバッファインジケータであることが理由です。
一つ一つの追加メンバについて解説していくので、ゆっくりと理解を深めていきましょう。
メンバ配列「signal」はストキャスティクスのシグナルライン値を格納する
アクセスレベル=privateのメンバ配列signal[]は、ストキャスティクスのシグナルライン値を格納するのに使います。
シングルバッファインジケータである移動平均線の時は、インジケータ値を格納する配列は親クラスのCBaseIndicatorクラスのメンバ変数配列「main」だけで事足りたのですが、ストキャスティクスはメインラインとシグナルラインの2つのラインで構成されるマルチバッファインジケータなので、インジケータ値を格納する配列も2つ必要になります↓
ストキャスティクスのメインラインについては親クラスのCBaseIndicatorクラスのメンバ変数配列「main」に格納されます。
※なお、メンバ配列signal[]のアクセスレベルをprotectedではなく、privateとしているのは、これ以上クラスを派生させる必要がない、という判断をしている為です。クラスを作成する過程において、もし「CDerivediStochastic」クラスからさらに派生クラスを作る場合はprotectedにしても構わない、という事になります。
仮想関数「Init」の仮引数と処理実装記述をCDerivediStochasticクラスで再定義する
追加メンバの「Init」は親クラス「CBaseIndicator」で定義した仮想関数です。
「CDerivediMA」クラスでも行った処理ではありますが、移動平均線とストキャスティクスではハンドル値を取得する関数も違うので、別途仮想関数 「Init」」を再定義しなおす必要があります。
※詳細は前回講座記事の『メンバ関数「Init」は戻り値だけを定めた仮想関数』セクションをご覧ください。
親クラス「CBaseIndicator」の時には、戻り値のデータ型がint型であるという事と、、return演算子で戻す値がアクセスレベル=protectedのメンバ変数「handle」、ということだけでした。
従って、派生クラスである「CDerivediStochastic」クラスで、改めて仮引数と処理実装記述を設定します。
CDerivediStochasticクラスにおける仮想関数「Init」の仮引数について
「CDerivediStochastic」クラスにおける、仮想関数 「Init」の仮引数は以下のようになっています。
int Init(string parSymbol,
ENUM_TIMEFRAMES parTimeframe,
int parKPeriod,
int parDPeriod,
int parSlowing,
ENUM_MA_METHOD parMAMethod,
ENUM_STO_PRICE parPrice);
仮引数は移動平均線の値を取得する=iStochastic関数の各引数に記述される想定ですので、iStochastic関数の各引数に完全対応した形になっています。
※iStochastic関数の各引数についてはコチラのリンクをご参照ください。
CDerivediStochasticクラスにおける仮想関数「Init」の処理実装記述について
「CDerivediStochastic」クラスにおける仮想関数 「Init」の処理実装記述については以下のようになっています。
int CDerivediStochastic::Init(string parSymbol, ENUM_TIMEFRAMES parTimeframe, int parKPeriod, int parDPeriod, int parSlowing, ENUM_MA_METHOD parMAMethod, ENUM_STO_PRICE parPrice)
{
handle = iStochastic(parSymbol,parTimeframe,parKPeriod,parDPeriod,parSlowing,parMAMethod,parPrice);
return(handle);
}
{}内の処理実装記述では、iStochastic関数を呼び出して、親クラスであるCBaseIndicatorクラスのメンバ変数「handle」に、取得したハンドル値を格納します。
※メンバ変数「handle」のアクセスレベルはCBaseIndicatorクラス内でprotectedに設定されていますので、派生クラスである「CDerivediStochastic」クラスのメンバ関数からでもアクセスができます。
あとは実際にEAを自作するメインプログラムにおいて、今回処理実装記述を施した「Init」関数(「CDerivediStochastic」クラスのメンバ)とメンバ関数「Main」(CBaseIndicatorクラスのメンバ)、及びこの後解説するSignal関数を呼び出すことによって、ストキャスティクスのメインラインやシグナルラインの値を自由に取得する事ができます。
CDerivediStochastic関数はインスタンス生成時に、配列signalの時系列をセットするコンストラクタ
アクセスレベル=publicに宣言したCDerivediStochastic関数はインスタンス生成時に、配列「signal」の時系列をセットするコンストラクタです。
親クラスのコンストラクタであるCBaseIndicator関数も配列を時系列にセットする関数なのですが、CBaseIndicator関数は基本的にバッファ番号「0」のインジケータ値を格納する配列に対し、時系列セットを施すようになっています。
バッファ番号「0」のインジケータ値は、ストキャスティクスにおいてはメインラインの値になります。
従って、ストキャスティクスの値を正確に取ることを目的とした「CDerivediStochastic」クラスにおいては、『シグナルラインの値を格納する配列「signal」にも時系列セットを施すコンストラクタ』が必要になる訳です。
※コンストラクタについては以下の記事をご参照ください。
・MQL5 EA講座 第52回「クラスについて5 -コンストラクタ-」
コンストラクタ、CDerivediStochastic関数の処理実装記述について
コンストラクタ、CDerivediStochastic関数の処理実装記述は以下の通りです。
CDerivediStochastic::CDerivediStochastic(void)
{
ArraySetAsSeries(signal,true);
}
コンストラクタは戻り値を取らないので、データ型はvoid型(=型なし)になります
ArraySetAsSeries関数を使い、配列「signal」に時系列セットを施します。
メンバ関数「Signal」はシグナルラインの値を取得して戻り値として返す
メンバ関数「Signall」はインジケータの値を取得して戻り値として返す関数です。
メインプログラムで呼び出す想定なので、アクセスレベルはpublicとなります。戻り値のデータ型はdouble型となります。
メンバ関数「Signal」の処理実装記述について
メンバ関数「Signal」の処理実装記述については以下の通りです。
double CDerivediStochastic::Signal(int parShift=0)
{
CopyBuffer(handle,1,0,MAX_COPY,signal);
double value = NormalizeDouble(signal[parShift],_Digits);
return(value);
}
仮引数「parIndex」には、シグナルラインの値を取得したい時系列のインデックス番号を指定します。
仮引数「parIndex」の初期値は「0」にしてあります。従って、メインプログラムで引数の記述を省略した場合、現在足のシグナルライン値を取得する事になります。
{}内の処理実装記述についてですが、CopyBuffer関数を使い、アクセスレベル=privateの配列「signal」にシグナルライン値をコピーします。CopyBuffer関数の第1引数には、これもアクセスレベル=protectedの変数「handle」を記述します。
第2引数にはバッファ番号を記述する訳ですが、ストキャスティクスのバッファ番号は
メインライン→「0」
シグナルライン→「1」
となっていますので、第2引数には「1」を記述します。
※CopyBuffer関数の詳細についてはコチラのリンクをご確認ください。
配列「signal」に格納されたシグナルライン値は、NormalizeDouble関数を使って正規化します。
正規化とは、プログラムが取り扱うルールに則って値を整える作業
のことを指します。
NormalizeDouble関数の第1引数には正規化する対象、すなわちsignal[parIndex]を記述します。
※定義済み変数については↓の記事をご参照ください。
正規化して、値を整えたsignal[parIndex]を、double型のローカル変数「value」 に代入します。
最後に変数「value」をreturn演算子で戻り値として返して処理実装記述は終了です。
実際にメインプログラムでCDerivediStochasticクラスを使い、ストキャスティクスのの値を取得してみる。
「CDerivediStochastic」クラスの各メンバの処理実装記述が終わった所で、今度は実際に、EAを自作する事を想定してメインプログラム内で「CDerivediStochastic」クラスを使い、ストキャスティクスの値を取得する記述をしてみましょう。
//+------------------------------------------------------------------+
//| CDerivediStochasticClassExample.mq5 |
//| MQL5ssei |
//| https://mqlinvestmentlab.com/ |
//+------------------------------------------------------------------+
#property copyright "MQL5ssei"
#property link "https://mqlinvestmentlab.com/"
#property version "1.00"
//OriginalIndicators.mqhファイルのインクルード
#include <OriginalIndicators.mqh>
//CDerivediStochasticクラスのインスタンスを宣言
CDerivediStochastic Stocha;
//必要なパラメータ
input int KPeriod=5;//K%の期間
input int DPeriod=3;//D%の期間
input int Slowing=3;//スローイングの期間
input ENUM_MA_METHOD StochaMethod=MODE_SMA;//ストキャス計算に使う移動平均の種類
input ENUM_STO_PRICE StochaPrice=STO_LOWHIGH;//ストキャス計算に使う価格種類
int OnInit()
{ //Init関数を呼び出してストキャスティクスのハンドル値を取得
Stocha.Init(_Symbol,_Period,KPeriod,DPeriod,Slowing,StochaMethod,StochaPrice);
return(INIT_SUCCEEDED);
}
void OnTick()
{
double mainLine=Stocha.Main();
double signalLine=Stocha.Signal();
Print("メインライン=",mainLine,",シグナルライン=",signalLine);
}
//+------------------------------------------------------------------+
OriginalIndicators.mqhファイルのインクルードする
まずは「OriginalIndicators.mqh」ファイルをメインプログラムのグローバル領域にインクルードします。
//OriginalIndicators.mqhファイルのインクルード
#include <OriginalIndicators.mqh>
CDerivediStochasticクラスのインスタンスを宣言する
「OriginalIndicators.mqh」ファイルをインクルードし、「CDerivediStochastic」クラスを使えるようになったので、今度は「CDerivediStochastic」クラスのインスタンスを宣言します。
//CDerivediStochasticクラスのインスタンスを宣言
CDerivediStochastic Stocha;
インスタンス名は「Stocha」としました。
各種input変数を宣言する
インスタンスを宣言した後は、各種input変数を宣言します。
input int KPeriod=5;//K%の期間
input int DPeriod=3;//D%の期間
input int Slowing=3;//スローイングの期間
input ENUM_MA_METHOD StochaMethod=MODE_SMA;//ストキャス計算に使う移動平均の種類
input ENUM_STO_PRICE StochaPrice=STO_LOWHIGH;//ストキャス計算に使う価格種類
この部分は講座記事第108回の「インジケータ関数の引数に記述するための値をinput変数で設定する」セクション(ストキャスティクス編)と全く同じです。
<参照>
OnInit関数内にCDerivediStochasticクラスのInit関数を呼び出す
続いてOnInit関数内に「CDerivediStochastic」クラスの「Init」関数を呼び出します。
int OnInit()
{ //Init関数を呼び出してストキャスティクスのハンドル値を取得
Stocha.Init(_Symbol,_Period,KPeriod,DPeriod,Slowing,StochaMethod,StochaPrice);
return(INIT_SUCCEEDED);
}
「CDerivediStochastic」クラスの「Init」関数は、iStochastic関数を使ってストキャスティクスのハンドル値を呼び出す機能を担っています。
ハンドル値の取得作業は、1度だけ行えば事足りるので,EAをMT5チャートに挿入する時にだけ処理を行うOnInit関数 内で行います。
OnTick関数内でCDerivediStochasticクラスのMain関数とSignal関数を呼び出す
最後にOnTick関数内で「CDerivediStochastic」クラスのメンバ関数「Main」とSignal関数を呼び出します。
void OnTick()
{
double mainLine=Stocha.Main();
double signalLine=Stocha.Signal();
Print("メインライン=",mainLine,",シグナルライン=",signalLine);
}
double型のローカル変数「mainLine」を宣言し、そこにはメンバ関数「Main」の戻り値を、
同じくdouble型のローカル変数「signalLine」を宣言し、そこにはSignal関数の戻り値を、それぞれ代入します。
Print関数で値を出力させてみた挙動は以下のようになっています。
「CDerivediStochastic」クラスを利用したストキャスティクスの取得手順は以上になります。
まとめ
今回は、前回第109回で作った、基礎クラス(=CBaseIndicatorクラス)を元にして、今後、どんなインジケータを使おうとしても滞りなく値を取得出来るようにするための派生クラスを作りました。
作った派生クラスは、
シングルバッファインジケータの例として移動平均線の値を取得する「CDerivediMA」クラス
マルチバッファインジケータの例としてストキャスティクスの値を取得する「CDerivediStochastic」クラス
の2つですが、MQL5の組み込み関数があるインジケータであれば、今回紹介した手順に従って、使いたい組み込みインジケータの派生クラスを自由に作ることができます。
「OriginalIndicators.mqh」ファイルに作った派生クラスを集約させておけば、EA開発の際に、簡単に取得したいインジケータの値をメインプログラムから取得できるようになります。
EA開発の可能性がだいぶ広がったと感じられるのではないでしょうか?
※現時点での「OriginalIndicators.mqh」ファイルの記述内容全体は以下のようになっています。
//+------------------------------------------------------------------+
//| OriginalIndicators.mqh |
//| MQL5ssei |
//| https://mqlinvestmentlab.com/ |
//+------------------------------------------------------------------+
#property copyright "MQL5ssei"
#property link "https://mqlinvestmentlab.com/"
//インジケータ値を配列にコピーす数を規定
#define MAX_COPY 100
//インジケータに共通する処理を担う基礎クラス
class CBaseIndicator
{
protected:
int handle;//インジケータのハンドル値を格納する変数
double main[];//インジケータの値を格納する配列
public:
CBaseIndicator(void);//コンストラクタ
double Main(int parIndex=0);
void Release();
virtual int Init() { return(handle); }
};
CBaseIndicator::CBaseIndicator(void)
{
ArraySetAsSeries(main,true);
}
double CBaseIndicator::Main(int parIndex=0)
{
CopyBuffer(handle,0,0,MAX_COPY,main);
double value = NormalizeDouble(main[parIndex],_Digits);
return(value);
}
void CBaseIndicator::Release(void)
{
IndicatorRelease(handle);
}
class CDerivediMA : public CBaseIndicator
{
public:
int Init(string parSymbol,ENUM_TIMEFRAMES parTimeframe,int parMAPeriod,int parMAShift,ENUM_MA_METHOD parMAMethod,ENUM_APPLIED_PRICE parMAPrice);
};
int CDerivediMA::Init(string parSymbol,ENUM_TIMEFRAMES parTimeframe,int parMAPeriod,int parMAShift,ENUM_MA_METHOD parMAMethod,ENUM_APPLIED_PRICE parMAPrice)
{
handle = iMA(parSymbol,parTimeframe,parMAPeriod,parMAShift,parMAMethod,parMAPrice);
return(handle);
}
class CDerivediStochastic : public CBaseIndicator
{
private:
double signal[];
public:
int Init(string parSymbol, ENUM_TIMEFRAMES parTimeframe, int parKPeriod, int parDPeriod, int parSlowing, ENUM_MA_METHOD parMAMethod, ENUM_STO_PRICE parPrice);
double Signal(int parShift=0);
CDerivediStochastic(void);
};
int CDerivediStochastic::Init(string parSymbol, ENUM_TIMEFRAMES parTimeframe, int parKPeriod, int parDPeriod, int parSlowing, ENUM_MA_METHOD parMAMethod, ENUM_STO_PRICE parPrice)
{
handle = iStochastic(parSymbol,parTimeframe,parKPeriod,parDPeriod,parSlowing,parMAMethod,parPrice);
return(handle);
}
CDerivediStochastic::CDerivediStochastic(void)
{
ArraySetAsSeries(signal,true);
}
double CDerivediStochastic::Signal(int parShift=0)
{
CopyBuffer(handle,1,0,MAX_COPY,signal);
double value = NormalizeDouble(signal[parShift],_Digits);
return(value);
}
今回は以上とさせていただきます。
最後までお読みいただきありがとうございました。