EAでインジケータを使用する P215
ほぼすべてのEAは、インジケータを使用して取引シグナルを生成します。この章では、オンラインまたはMetaTrader5の\MQL5\Indicators\Examplesファイルにあるカスタムインディケータと同様に、EAでMetaTraderの組み込みインディケータを使用する方法を検討します。インジケータの使用を簡素化するクラスを作成し、いくつかの一般的なインジケータベースの取引シグナルを調べます。
シングルBufferインジケータ P215
この本の前半で、単純なEAで移動平均インジケータを使用しました。EAに移動平均インジケータを追加するコードは次のとおりです。
//入力変数
input int MAPeriod = 10;
input int MAShift = 0;
input ENUM_MA_METHOD MAMethod = MODE_EMA;
input ENUM_APPLIED_PRICE MAPrice = PRICE_CLOSE;
//OnTick()イベントハンドラ
double ma[];
ArraySetAsSeries(ma, true);
int maHandle = iMA(_Symbol, _Period, MAPeriod, MAShift, MAMethod, MAPrice);
CopyBuffer(mahandle, 0, 0, 3, ma);
double currentMA = ma[0];
入力変数には、移動平均パラメータを調節するための4つの設定が含まれます。MAPeriodは、インジケータの期間を調整します。MAShiftは、インジケータをチャート上で前方または後方にシフトします。MAMethodは指標の計算方法(単一・指数など)を変更し、MAPriceは移動平均の計算に使用される価格シリーズ(終値・始値)を選択します。
図17.1-日足チャートの30期間の指数移動平均
OnTick()イベントハンドラで、移動平均データを保持するma[]配列を初期化します。ArraySetSeries()関数は、ma[]配列として設定します。iMA()関数は入力変数を受け取り、指定された銘柄とチャート期間の指標を計算します。すべての組み込みのMetaTraderインジケータには、同様の機能があります。テクニカル指標の下のMQL5リファレンスでそれらを表示できます。
iMA()インジケータの関数定義は次のとおりです。
int iMA(
string symbol, //シンボル名
ENUM_TIMEFRAMES perido, //限目
int ma_period, //平均期間
int ma_shift, //水平シフト
ENUM_MA_METHOD ma_method, //スムージングタイプ
ENUM_APPLIED_PRICE pplied_price //価格またはハンドルのタイプ
);
全てのテクニカル指標関数は、シンボルと期間のパラメータで始まります。残りのパラメータはインジケータによって異なります。移動平均インジケータには、調整可能な4つのパラメータがあります。一部のインジケータにはパラメータが1つまたは2つしかなく、いくつかのインジケータには全くパラメータがありません。移動平均インジケータの入力変数は次のとおりです。
//入力変数
input int MAPeriod = 10;
input int MAShift = 0;
input ENUM_MA_METHOD MAMethod = MODE_EMA;
input ENUM_APPLIED_PRICE MAPrice = PRICE_CLOSE;
各パラメータの型に注意してください。例えば、iMA()関数のma_methodパラメータはENUM_MA_METHODタイプを使用します。したがって、対応する入力パラメータは同じタイプでなければなりません。この場合、MAMethod入力変数はENUM_MA_METHOD型を使用するため、これがma_methodパラメータに渡す値になります。
使用する必要がある特定のテクニカル指標関数の関数宣言を確認することで、EAに追加する必要がある入力パラメータを決定できます。移動平均インジケータの4つの入力変数はiMA()関数のパラメータと一致することに注意してください。
iMA()関数は、ほかのすべてのインジケータ関数と同様に、インジケータの一意の識別子であるインジケータハンドルを返します。このハンドルは、データのコピーやインジケータの使用からの削除など、インジケータに関連するすべてのアクションに使用されます。
CopyBuffer()関数は、指定された指標バッファから配列にデータをコピーするために使用されます。その後、配列を使用して指標データにアクセスできます。CopyBuffer()関数の関数定義は次のとおりです。
int CopyBuffer(
int indicator_handle, //インジケータハンドル
int buffer_num, //指標バッファ番号
int start_pos, //開始位置
int count, //コピーするバーの量
double buffer //コピー先のターゲット配列
);
indicator_handleパラメータは、iMA()またはその他のインジケータ関数によって返されるインジケータハンドルを受け入れます。buffer_numパラメータはデータのコピー元の使用バッファの番号です。ほとんどのインジケータにはバッファーが1つしかありませんが、2つ、3つまたはそれ以上のものもあります。これについては後程詳しく説明します。残りのパラメータはおなじみのはずです。start_posパラメータはコピーを開始する開始位置、countはコピーの数、bufferはコピー先の配列の名前です。
移動平均インジケータの例をもう一度見てみましょう。
int maHanble = iMA(_Symbol, _Period, MAPeriod, MAShift, MAMethod, MAPrice);
CopyBuffer(mahandle, 0, 0, 3, ma);
double currentMA = ma[0];
iMA()関数は指標ハンドルを返し、それをmaHandle変数に保存します。CopyBuffer()関数は、maHandle値の最初のパラメータとして受け取ります。移動平均線は1行しかないため、バッファー番号は0です。最新のバー(インデックス0)から開始し、3バー分のデータをma[]配列にコピーします。ma[]配列にデータが入力され、使用できるようになりました。ma[0]を呼び出すと、現在のバーの移動平均値が返されます。
単一のバッファのみを使用する2番目のインジケータを見てみましょう。RSIインジケータは非常に人気があり、極端な価格を特定するために良く使用されます。RSIインジケータの関数定義は次のとおりです。
int iRSI(
string symbol, //シンボル名
ENUM_TIMEFRAMES period, //限目
int ma_period, //平均期間
ENUM_APPLIED_PRICE applied_price //価格またはハンドルのタイプ
);
MA()関数と同様に、最初の2つのパラメータはシンボルとピリオドです。RSIは2つの入力パラメータを取ります。1つは平均期間(ma_period)用で、もう1つは価格系列(適用価格)用です。ちなみに、適用された価格パラメータを持つインジケータ関数は、代わりにインジケータハンドルを渡すことができます。つまり、別のインジケータから派生した価格シリーズを使用できます。
図17.2-RSIインジケータ
RSIインジケータをEAに追加する方法は次のとおりです。
//入力パラメータ
input int RSIPeriod = 10;
input ENUM_APPLIED_PRICE RSIPrice = PRICE_CLOSE;
//OnTick()イベントハンドラ
double rsi[];
ArraySetAsSeries(rsi, true);
int handle = iRSI(_Symol, _Period, RSIPeriod, RSIPrice);
CopyBuffer(handle, 0, 0, 3, rsi);
double rsi = [0];
double lastRsi = rsi[1];
プログラムの最初で、入力変数RSIPeriodとRSIPriceを適切な型で宣言します。OnTick()イベントハンドラ内で、rsi[]配列を宣言し、シリーズ配列として設定します。最後に、ハンドルパラメータをiRSI()関数に渡し、インジケータハンドルをハンドル変数に保存します。最後に、ハンドル変数をCopyBuffer()関数に渡し、3バー分のデータがrsi[]配列にコピーされます。
rsi変数とlastRsi変数には、現在の足と前の足のRSI値が割り当てられます。たとえば、これらの変数を比較して、RSIが上昇しているか下降しているかを判断できます。
マルチBufferインジケータ P218
複数の行(および複数のバッファー)を持つインジケータを使用する場合、プログラミングにすべてのデータを所得するために、いくつかの配列とCopyBuffer()関数を使用する必要があります。確率的指標から始めましょう。ストキャスティクスは、RSIと同様のオシレータです。メインのストキャスティクスラインに加えて、2つ目のシグナルラインも存在します。
図17.3-ストキャスティクス(確率的)インジケータ。赤い破線は信号線です。
EAに確率的指標を追加する方法は次のとおりです。
//入力パラメータ
input int KPeriod = 10;
input int DPeriod = 3;
input int Slowing = 3;
input ENUM_MA_METHOD StochMethod = MODE_SMA;
input ENUM_STO_PRICE StochPrice = STO_LOWHIGH;
//OnTick()イベントハンドラ
double main[], signal[];
ArraySetAsSeries(main, true);
ArraySetAsSeries(signal, true);
int handle = iStochastic(_Symbol, _Period, KPeriod, DPeriod, Slowing, StochMethod, StochPrice);
CopyBuffer(handle, 0, 0, 3, main);
CopyBuffer(handle, 1, 0, 3, signal);
double currentStoch = main[0];
double currentSignal = signal[0];
確率的インジケータには、5つの入力パラメータと2つのバッファーがあります。配列main[]とsignal[]を宣言して、確率的指標データを保持します。両方の配列は、ArraySetAsSeries()関数を使用して系列配列として設定されます。iStochastic()関数は指標を初期化し、指標ハンドルをハンドル変数に返します。iStochastic()の関数定義は次のとおりです。
int iStochastic(
string symbol, //シンボル名
ENUM_TIMEFRAMES period, //限目
int Kperiod, //K期間
int Dperiod, //D期間
int slowing, //最終平滑化
ENUM_TIMEFRAMES ma_method, //平滑化のタイプ
ENUM_TIMEFRAMES price_field //確率計算法
);
上記の入力変数をiStochastic()関数のパラメータと比較し、ma_methodおよびPrice-fieldパラメータの型に注意してください。ENUM_STO_PRICE列挙体は、確率指標(安値/高値または終値/終値)の計算方法を設定するために使用されます。
MQL5リファレンスのiStochastic()エントリーを見ると、説明に次の注記が表示されます。
Note
The buffer numbers: 0 – MAIN_LINE, 1 – SIGNAL_LINE.
これらは、2つの確率的インジケータラインのバッファ番号です。CopyBuffer()関数のbuffer_numパラメータにバッファ番号を渡します。CopyBuffer()関数は、その指標バッファから指標された配列にデータをコピーします。インジケータの各バッファに対してこれを行う必要があります。
CopyBuffer(handle ,0, 0, 3, main);
CopyBuffer(handle, 1, 0, 3, signal);
バッファ番号は太字で強調表示されています。バッファ0(MAIN_LINE)の内容はmain[]配列にコピーされ、バッファ1(SIGNAL_ LINE)の内容はsignal[]配列にコピーされます。main[]配列はメイン確率線(%K線とも呼ばれます)の値を保持し、signal[]配列はシグナル線(%D線とも呼ばれます)の値を保持します。
マルチバッファインジケータを追加する手順は同じです。関連する指標関数のMQL5リファレンスエントリのバッファ番号に注意してください。次に、適切な配列を宣言し、それらをシリーズとして設定し、インジケータを初期化し、各バッファを対応する配列にコピーします。
Cindicatorクラス P220
プログラムにインジケータを追加するプロセスを簡素化するクラスを作成します。すべてのインジケータで共有されるすべての変数と関数を含む基本クラスを作成することから始めます。次に、各インジケータの特定のニーズに対応するこの基本クラスから派生した新しいクラスを作成します。
前セクションで取り上げたすべての組み込みインジケータには、いくつかの共通点があります。すべての指標は、バッファデータを保持するために少なくとも1つの配列を使用します。その配列は、シリーズ配列として設定する必要があります。指標ハンドルを保持する変数が必要です。そして、バッファデータをコピーして配列にアクセスする方法が必要です。最後に、必要に応じてプログラムからインジケータを削除できるようにする必要があります。
インジケータの基本クラスは、これらすべてのタスクを実行します。基本クラスにCIndicatorという名前を付けます。\MQL5\Include\Mql5Book\Indicators.mqhインクルードファイルに配置されます。このファイルは、すべてのインジケータ関連のクラスと関数を保持するために使用されます。
CIndicatorクラスのクラス宣言は次のとおりです。
class CIndicator
{
protected:
int handle;
double main[];
public:
CIndicator(void);
double Main(int pShift=0);
void Release();
virtual int Init() { return(handle); }
};
CIndicatorクラスには、2つの保護された変数と4つのパブリック関数があります。protectedキーワードは、変数の内容がCIndicatorクラス内および派生クラス内でのみアクセス可能であることを意味します。ハンドル変数にはインジケータハンドルが含まれ、メインの[]配列にはバッファデータが保持されます。
4つのパブリック関数があります。CIndicator()関数はクラスコンストラクタ―です。このクラスに基づくオブジェクトが作成されると、コンストラクターが自動的に実行されます。CIndicatorクラスのコンストラクターを見てみましょう。
CIndicator::CIndicator(void)
{
ArraySetSeries(main, true);
}
クラスコンストラクタ―は、ArraySetAsSeries()関数を使用して、main[]配列をシリーズとして設定するだけです。CIdicatorクラスに基づいてオブジェクトを作成するするたびに、main[]配列が宣言され、系列配列として設定されます。
次はMain()関数です。
double CIndicator::Main(int pShift=0)
{
CopyBuffer(handle, 0, 0, MAX_COUNT, main);
double value = NormalizeDouble(main[pShift], _Digits);
return(value);
}
有効なインジケータハンドルがすでにあると仮定すると、Main()関数はバッファデータをmain[]配列にコピーし、pShiftパラメータで指定されたバーのデータにアクセスします。値を返す前に、NormalizeDouble()関数を使用して値をシンボル価格の有効桁数に収めます。派生クラスの作成を開始する時にインジケータハンドルを作成する関数を記述します。
次に、Release()関数があります。この関数は、インジケータが不要になった場合に単にメモリーからインジケータを開放します。
void CIndicator::Release(void)
{
IndicatorRelease(handle);
}
最後に、Init()関数は仮想関数であり、その機能は派生クラスで定義されます。関数を仮想として宣言することにより、プログラマーがすべての派生クラスでInit()関数を定義する必要があることをコンパイラ―に伝えます。仮想関数については、この章の後半で説明します。
virtual int Init()
{
return(handle);
}
派生クラス P222
CIndicatorクラスは、MateTraderの組み込みインジケータからデータを初期化および取得するために使用される派生クラスの基礎になります。各インジケータの実装は異なるため、使用するインジケータごとに個別のクラスを作成する必要があります。
移動平均インジケータから始めましょう。移動平均にはバッファが1つしかないため、最小限の労力で派生クラスを作成できます。CiMAクラスのクラス宣言は次のとおりです。
Class CiMA : public CIndicator
{
public:
int Init(string pSymbol, ENUM_TIMEFRAMES pTimeframe, int pMAPeriod,
int pMAShift, ENUM_MA_METHOD pMAMethod, ENUM_APPLIED_PRICE pMAPrice);
};
CiMAクラスには、インディケータの初期化に使用されるパブリック関数Init()が1つあります。クラス名の後の:public CIndicatorに注意してください。これは、CiMAクラスがCIndicatorから派生していることを示します。CiMAクラスは、CIndicatorクラスからpublicおよびprotected関数と変数をすべて継承します。
CIndicatorでは、Init()関数が仮想関数として宣言されていることに注意してください。これは、CIndicatorのすべての派生クラスがInit()関数を実装する必要があることを意味します。プログラマーがInit()関数を実装せずにプログラムをコンパイルしようとすると、エラーが発生します。
CiMA::Init()関数の関数宣言は次のとおりです。
int CiMA::Init(string pSymbol, ENUM_TIMEFRAMES pTimefram, int pMAPeriod,
int pMAShift, ENUM_MA_METHOD pMAMethod, ENUM_APPLIED_PRICE pMAPeriod)
{
handle = iMA(pSymbol, pTimeframe, pMAPeriod, pMAShift, pMAMethod, pMAPrice);
return(handle);
}
Init()クラスは単にiMA()関数を呼び出し、CIndicatorクラスで宣言されたハンドル変数にインジケータハンドルを保存します。あとは、CIndicatorで宣言されたMain()関数を使用して移動平均データにアクセスするだけです。
EAでCiMAクラス(およびその親クラスであるCIndicator)を使用する方法を次に示します。
//CiMAクラスに基づいてオブジェクトを作成します
#include <Mql5Book\Indicators.mqh>
CiMA MA;
//入力変数
input int MAPeriod = 10;
input ENUM_MA_METHOD MAMethod = 0;
input int MAShift = 0;
input ENUM_APPLIED_PRICE MAPrice = 0;
//OnInit()イベントハンドラ
MA.Init(_Symbol, _Period, MAPriod, MAShift, MAMethod, MAPrice);
//OnTick()イベントハンドラ
double currentMA = MA.Main();
EAソースコードファイルの先頭で、CiMAクラスに基づくオブジェクトを作成します。このオブジェクトをMAと名付けます。移動平均の設定を調節するために必要な入力変数も、ファイルの上部で宣言されています。
Init()関数は、OnInit()イベントハンドラから呼び出されます。EAが最初に初期化されるときに、OnInit()が一回実行されることに注意してください。インジケータを初期化する必要があるのは1回だけなので、OnInit()に配置するだけで問題なく動作します。また、悪影響を与えずにOnTick()イベントハンドラに配置することもできます。
現在のバーの移動平均値を取得するには、オプションのパラメータとしてバーインデックスを使用してMain()関数を呼び出すだけです。パラメータなしでMain()を呼び出したので、現在のバーの値を返します。例えば、前のバーの値を取得するには、MA.Main(1)を呼び出します。\MQL5\Experts\Mql5Book\Simple Expert Advisor with Functions.mq5ファイルは、移動平均データにアクセスするCiMAクラスで更新されました。
入力変数は別として、わずか2行のコードでインジケータを初期化できます。ファイルの先頭にあるオブジェクト宣言と、インジケータを初期化するInit()関数です。次に、覚えやすい関数を使用して指標値にアクセスできます。
複数のバッファを持つ指標を使用して、2番目の指標クラスを作成しましょう。この章の前半で確率的指標について説明しましたが、これには2つのバッファがあります。クラス宣言で追加のバッファ配列を宣言する必要があります。クラスコンストラクタは追加の配列を系列配列として設定します。最後に、追加の配列にアクセスするための関数を追加する必要があります。
class CiStochastic : public CIndicator
{
private :
double signal[] ;
public :
int Init(string pSymbol, ENUM_TIMEFRAMES pTimeframe, int pKPeriod, int pDPeriod,
int pSLowing, ENUM_MA_METHOD pMAMethod, ENUM_STO_PRICE pPrice);
double Signal(int pShift=0);
CiStochastic(void);
};
CIndicatorクラスで仮想関数として宣言されたInit()関数に加えて、CiStochasticクラスにはいくつかの追加メンバーがあります。signal[]という名前のプライベート配列は、シグナルまたは%Dラインのインジケータ値を保持します。Public Signal()関数はこのデータにアクセスするために使用されます。また、クラスのコンストラクターも追加しました。
CiStochatic : : CiStochastic(void)
{
ArraySetAsSeries(signal, true);
}
CIndicatorクラスのコンストラクターと同様に、CiStochasticコンストラクタは単にsignal[]配列を系列配列として設定します。複数のバッファを持つすべての指標に対してこれを行う必要があります。
Init()およびSignal()関数の関数宣言は次のとおりです。
int CiStochastic::Init(string pSymbol, ENUM_TIMEFRAMES pTimeframe, int pKPeriod,
int pDPeriod, int pSlowing, ENUM_MA_METHOD pMAMethod, ENUM_STO_PRICE pPrice)
{
handle = iStochastic(pSymbol, pTimeframe, int pKPeriod, pDPeriod, pSlowing, pMAMethod, pPrice);
return(handle);
}
double CiStochastic : : Signal(int pShift=0)
{
CopyBuffer(handle, 1, 0, MAX_COUNT, signal);
double value = NormalizeDouble(signal[pShift], _Digits);
return(value);
}
Init()関数は、入力パラメータをiStochastic()関数に渡し、インジケータハンドルをハンドル変数に保存します。Signal()関数は、ストキャスティクスインジケータのバッファ1からデータをsignal[]配列にコピーし、指定されたバーの値を返します。マルチバッファインジケータクラスのすべての追加インジケータバッファに対して同様の関数を追加する必要があります。
移動平均を追加したのと同じ方法でEAに確率的指標を追加します。―オブジェクトを宣言し、指標を初期化し、指標データにアクセスします。
//CiStochasticクラスに基づいてオブジェクトを作成します。
#include <Mql5Book\Indicators.mqh>
CiStochastic Stoch;
//入力変数
input int KPeriod = 10;
input int DPeriod = 3;
input int Slowing = 3;
input ENUM_MA_METHOD StochMethod = MODE_SMA;
input ENUM_STO_PRICE StochPrice = STO_LOWHIGH;
//OnInit()イベントハンドラ
Stoch.Init(_Symbol, _Period, KPeriod, DPeriod, Slowing, StochMethod, StochPrice);
//OnTick()イベントハンドラ
double currentStoch = Stoch.Main();
double currentSignal = Stoch.Signal();
ほんの数行のコードを使用して、EAに確率的インジケータを追加しました。Stochという名前のCiStochasticクラスに基づいてオブジェクトを宣言しました。Init()を使用して、OnInit()イベントハンドラでインジケータを初期化しました。また、指標データを取得するためにMain()とSignal()の2つの関数があります。currentStochおよびcurrentSignal変数には、現在のバーの%Kおよび%Dライン値が含まれています。
オプジェクトの初期化 P225
派生クラスがどのように機能するかについての理解を深めるために、CiStochasticオブジェクトの作成について説明しましょう。まず、オブジェクトを初期化します。
CiStochastic Stoch;
このプログラムは、CIndicatorクラスの保護メンバーとパブリックメンバーを初期化します。以下にリストされている変数とオブジェクトはCiStochasticクラスの一部となり、パブリックメンバーはStochオブジェクトを通じてアクセスできます。
class CIndicator
{
protected:
int handle;
double main[];
public:
CIndicator(void);
double Main(int pShift=0);
void Release();
};
次に、CIndicatorクラスのコンストラクターが実行されます。Main[]配列は系列配列として設定されます。
CIndicator : : CIndicator(void)
{
ArraySetAsSeries(main, true);
}
CiStochasticクラスメンバーは次に初期化されます。
class CiStochastic : public CIndicator
{
private:
double signal[];
public:
int Init(string pSymbol, ENUM_TIMEFRAMES pTimeframe, int pKPeriod, int pDPeriod,
int pSlowing, ENUM_MA_METHOD pMAMethod, ENUM_STO_PRICE pPrice);
double Signal(int pShift=0);
CiStochastic(void);
};
次に、CiStochasticクラスのクラスコントラクターが実行されます。Signal[]配列は、一連の配列として設定されます。
CiStochastic : : CiStochastic(void)
{
ArraySetAsSeries(signal, true);
}
Stochオブジェクトを使用する準備が整いました。ハンドル変数は、メインの[]およびsignal[]配列と同様に、プログラマがアクセスできない保護されたメンバーまたはプライベートメンバーです。これらのメンバーとは、パブリック関数Init()、Main()、Signal()、およびRelease()を使用して対話します。
\MQL5\Include\Mql5Bool\Indicators.mqhファイルには、MetaTrader5の最も一般的な組み込みインジケータのクラスが含まれています。リストされていないインジケータのクラスを作成する必要がある場合は、この章にリストされている手法を使用して作成できます。
カスタムインディケータ P227
EAでカスタム指標を使用することもできます。カスタムインジケータを使用するには、インジケータ内のバッファの数とその使用方法を決定する必要があります。また、指標パラメータの名前とタイプを決定する必要があります。
カスタム指標は、MQL5コードベース、MQL5マーケット、またMetaTrader関連のフォーラムやウェブサイトからオンラインでダウンロードできます。MQ5ファイルがあれば、カスタムインディケータでの作業がはるかに簡単になります。EX5しか持っていない場合でも、プロジェクトでインジケータを使用することは可能ですが、もう少し調査作業が必要です。
MetaTrader5に標準装備されているカスタムインジケータの1つを使用してみましょう。ナビゲータウィンドゥのカスタムインジケータツリーには、多くの組み込みMetaTraderインジケータのカスタムインジケータの例といくつかのエクストラを含むサンプルサブツリーがあります。チャートにボリンジャーバンドをプロットするBBカスタムインジケータを使用します。
カスタムインジケータを調べる場合は[データ]ウィンドウ(Ctrl+D)を開いて、チャートにプロットされている線の数と、それらに割り当てられているラベルがある場合はそのラベルを確認します。BBインジケータには、Middle、Upper、Lowerの3つのラインがあります。
図17.4-BBカスタムインジケータ
MetaEditorでIndicators\Examples\BB.mq5ファイルを開きます。指標が使用するバッファまたはプロットの数と関連するバッファ番号を調べる必要があります。SetIndexBuffer()関数のOnInit()イベントハンドラを調べます。これにより、プログラムで定義された配列が特定の指標バッファ番号に割り当てられます。
SetIndexBuffer(0, ExtMLBuffer);
SetIndexBuffer(1, ExtTLBuffer);
SetIndexBuffer(2, ExtBLBuffer);
SetIndexBuffer(3, ExtStdDevBuffer, INDICATOR_CALCULATIONS);
SetIndexBuffer()関数のパラメータはバッファ番号です。インジケータには3行ありますが、コードは4つのバッファーを示しています!バッファ3のINDICATOR_CALCULATIONSパラメータに注意してください。これは、このバッファが内部計算のみに使用されることを示しています。各バッファが何をするのかを理解するにはもう少し検索を行う必要があります。
ファイルのすぐ下を見ると、3つのPlotIndexSetString()関数が表示されます。これらは、データウィンドウでラベルを設定するために使用されます。
PlotIndexSetString(0,PLOT_LABEL,“Bands(“+string(ExtBandsPeriod)+”)Middle”); PlotIndexSetString(1,PLOT_LABEL, “Bands(“+string(ExtBandsPeriod)+”) Upper”);
PlotIndexSetString(2,PLOT_LABEL, “Bands(“+string(ExtBandsPeriod)+”) Lower”);
これから、バッファー0が中央の線、バッファ1が上のバンド、バッファ2が下のバンドであると推測できます。バッファ番号がわかったので、ボリンジャーバンドインジケータの入力パラメータを計算してみましょう。入力変数は、ファイルの最上部近くにあります。
input int InpBandsPeriod=20; //期間
input int InpBandsShift=0; //シフト
input double InpBandsDeviations=2.0; //偏差
入力パラメータは3つあります。期間とシフト用の2つのint変数と、偏差用のdouble変数です。入力変数をカスタムインジケータファイルからEAファイルに自由にコピーアンドペーストしてください。必要に応じて、プログラム内の入力変数の名前を変更できます。
iCustom()関数 P228
iCutom()関数は、この章で前に説明した組み込みインジケータ関数と同様に機能します。MQL5リファレンスからの関数定義は次のとおりです。
Int iCustom(
string symbol, //シンボル名
ENUM_TIMEFRAMES period, //期間
string name //フォルダ/カスタムインジケータ名
・・・ //指標入力パラメータのリスト
);
他のテクニカル指標関数と同様に、iCustom()パラメータはSymbolとPeriodで始まります。nameパラメータは、インジケータ名からファイル拡張子を除いたものです。インジケータファイルは、\MQL5\Indicatorsフォルダーに配置する必要があります。ファイルがサブフォルダ―にある場合、サブフォルダー名は、二重スラッシュ(\\)で区切られた標識名の前になければなりません。例えば、BBインジケータは\MQL5\indicators\Examplesフォルダにあります。したがって、nameパラメータの値は「Exmples\\BB」になります。(二重スラッシュ(\\)はバックスラッシュのエスケープ文字であることを忘れないでください!)
iCustom()関数定義の…は、カスタムインジケータの入力パラメータの入力パラメータの場所です。BBカスタムインジケータには3つの入力パラメータがあります。これらのパラメータを、インジケータファイルに表示される順序でiCustom()関数に渡す必要があります。
input int InpBandsPeriod=20; //期間
input int InpBandsShift=0; //シフト
input double InpBandsDeviations=2.0; //偏差
タイプintのint型とdouble型の3つのパラメータをiCustom()関数に渡す必要があります。以下はiCustom()関数を使用してBBインジケータをEAに追加する方法の例です。
//入力変数
input int InpBandsPeriod=20; //期間
input int InpBandsShift=0; //シフト
input double InpBandsDeviations=2.0; //偏差
//OnTick()イベントハンドラ
double upper[], lower[], middle[];
ArraySetAsSeries(upper, true);
ArraySetAsSeries(lower, true);
ArraySetAsSeries(middle, true);
int bbHandle = iCustom(_Symbol, _Period, “Examples\\BB”, BandsPeriod, BandsShift, BandsDeviation);
CopyBuffer(bbHandle, 0, 0, 3, middle);
CopyBuffer(bbHandle, 1, 0, 3, upper);
CopyBuffer(bbHandle, 2, 0, 3, lower);
double bbMid = middle[0];
double bbUp = upper[0];
double bbLow = lower[0];
入力変数は、BBインジケータファイルに表示される順序で表示されます。それらの名前をBandsPeriod、BandsShift、およびBandsDeviationに変更しました。次に、指標データを保持するために使用する3つの配列(上部[]、下部[]、および中央[])を宣言し、それらを系統配列として設定します。iCustom()関数はBBインジケータを初期化し、インジケータハンドルを返し、それをbbHandle変数に保存します。BBインジケータは\Indicators\Examplesサブフォルダにあるため、iCustom()関数のnameパラメータに「Examples\BB」を使用することに注意してください。
iCustom()関数呼び出しのBandsPeriod、BandsShift、およびBandsDeviationパラメータに注意してください。カスタムインジケータのすべての入力パラメータを、表示される順序でiCustom()関数に渡す必要があります。パラメータも適切なデータ型である必要があります。インジケータの大部分は、int、doubleまたはstring型のいずれかを使用します。特定のカスタムインジケータパラメータに入力変数を追加したくない場合は、単にデフォルト値を渡します。例えば、BBインジケータのBandsShiftパラメータを変更する予定がない場合は、iCustom()関数呼び出しでBandsShiftを0に置き換えるだけです。
最後に、CopyBuffer()関数を使用して、指標バッファから配列にデータをコピーします。指標線を使用する予定がない場合は、データをコピーする必要はありません。例えば、BBインジケータの中央の線を使用する予定がない場合は、middle[]配列と、それを参照するArraySetAsSeries()およびCopyBuffer()関数を単純に省略します。
上記の手順を使用して、任意のカスタムインジケータをEAに追加できます。最初に、使用したいカスタムインディケータの対応するライン/プロットのバッファ番号に注意してください。次に、入力パラメータの名前とその方に注意してください。入力パラメータをEAに追加し、必要に応じて名前を変更したり省略したりします。入力パラメータ(または適切なデフォルト値)をインジケータ名とともにiCustom()関数に渡します。最後に、CopyBuffer()関数を使用して、準備した系列配列にバッファデータをコピーします。
カスタムインジケータクラスとは? P230
組み込みインジケータについては、それらをEAに簡単に追加できるようにするクラスを作成しました。残念ながら、MQL5でのカスタム指標の実装は、同じことを行うのが困難になっています。上で見たように、iCustom()関数は柔軟な数の入力パラメータを許可します。MQL5でクラスを作成する場合、同じことはできません。
MQL5プログラムにインジケータを追加する2つ目の方法、IndicatorCreate()関数があります。これは、固定数のパラメータとMqlParam構造体系のオブジェクトを使用して入力パラメータを渡します。しかし、この方法を使用すると、複雑さが増し、シンプルさや機能性が向上することはありません。したがって、この本ではこの方法については説明しません。
要約すると、EAにカスタム指標を追加したい場合は、iCustom()関数を使用して指標ハンドルを返し、次に前のセクションで説明したようにCopyBuffer()関数を使用してバッファデータをシリーズ配列にコピーする必要があります。
インジケータベースの取引シグナル P231
インジケータを使用して取引シグナルを作成する方法をいくつか見てみましょう。ほとんどすべての指標ベースの取引シグナルは、次のカテゴリのいずれかに分類されます。
- 指標線と価格の関係
- 2つ以上のインジケータライン間の関係
- 2本の棒の間の指標線の変化または傾き
- 固定値に対する指標の値
前の章の価格ベースのトレーディングシグナルに関するセクションでは、最初のカテゴリについて説明しました。価格が指標線の上または下にある時に、取引シグナルを作成できます。この章では、ボリンジャーバンドインジケータについて説明しました。価格/指標関係の例として、この指標を使用できます。
ボリンジャーバンドは、極端な価格で取引を開始するために使用できます。例えば、価格がバンドの外に移動した場合などです。これらの取引条件は次のように表現できます。
if(Price.Close() > bbUpper && PositionType(_Symbol) != POSITION_TYPE_BUY)
{
//買いポジションを開く
}
else if(Price.Close() < bbLower && PositionType(_Symbol) != POSITION_TYPE_SELL)
{
//売りポジションを開く
}
前の章で作成したCBarsクラスのClose()関数を使用して、現在の終値を表します。bbUper変数とbbLower変数は、それぞれボリンジャーバンドの上限と下限を表します。現在の終値が上限バンドを上回り、現在オープンしている買いポジションが無い場合は、買いポジションをオープンします。終値が下のバンドを下回っている場合、同じことが売りにも当てハマります。
2つ以上のインジケータラインを使用して、取引シグナルを作成できます。例えば、移動平均クロスは最も基本的なトレーディング戦略の1つです。高速移動平均と低速移動平均の2つの移動平均線を使用します。高速移動平均線が低速移動平均線を上回っている場合は、買いのシグナルであり、逆の場合は売りのシグナルです。
例えば、速いMAには10期間の指数移動平均を使用し、遅いMAには30期間の単純移動平均を使用します。
if(fastMA > slowMA && PositionType(_Symbol)!=POSITION_TYPE_BUY && glBuyPlaced == false)
{
//買いポジションを開く
}
if(fastMA < slowMA && PositionType(_Symbol)!=POSITION_TYPE_SELL && glSELLPlaced == false)
{
//売りポジションを開く
}
10EMA(fastMA変数)が30SMA(slow変数)よりも大きい場合、買いシグナルが発生します。逆の場合は、売りシグナルが発生します。
すべて同じウィンドウに描写されている場合は、異なるタイプのインジケータを使用することもできます。例えば、価格の代わりに前の例のボリンジャーバンドで移動平均を使用したい場合があります。
if(ma[1] > bbUpper && PositionType(_Symbol) ! = POSITION_TYPE_BUY)
{
//買いポジションを開く
}
この例では、前のバーの移動平均値(ma[1])がボリンジャーバンドの上限(bbUpper)より大きいかどうかを確認します。もしそうなら、買いシグナルが発生します。
ストキャスティクスインジケータのメインラインとシグナルラインなど、同じインジケータの2つのラインを比較することもできます。
if(stoch[1] > signal[1] && PositionType(_Symbol ) ! = POSITION_TYPE_BUY)
{
//買いポジションを開く
}
Stoch[]配列は指標のメインまたは%Kラインを表し、signal[]配列は%Dラインです。%Kラインが%Dラインよりも大きい場合、これは強気の状態を示します。
トレンドインジケータの場合、インジケータのトレンドの方向に基づいて取引を決定したい場合があります。これを行うには、最近のバーの指標値を前のバーの値と照合します。例えば、移動平均が上向きに傾斜しているときに買いシグナルを発生させたい場合は、最近閉じたバーの値を前のバーの値と比較できます。
if(ma[1] > ma[2] && PositionType(_Symbol ) ! = POSITION_TYPE_BUY)
{
//買いポジションを開く
}
この例では、最近閉じたバー(ma[1])の移動平均値が前のバーの値(ma[2])より大きいかどうかを確認します。もしそうなら、移動平均線は上昇傾向にあり、買いシグナルが発生します。これは、RSIやMACDなどのオシレータを含む、価格とともに上昇または下降する任意の指標で行うことができます。
多くのインジケータ、つまりオシレータは、別のチャートウィンドウに表示されます。価格に応じてプロットされるのではなく、価格の変化に対応します。他えば、RSIの最小値は0で、最大値は100です。RSI値が30未満の場合は売られすぎの状態を示し、70を超える場合は買われすぎの状態を示します。現在のRSI値を固定値と比較するだけで、これらの買われすぎと売られすぎの状態を確認できます。以下の例では、買いシグナルの一部として売られすぎの状態をチェックしています。
if(rsi[1] <= 30 && PositionType(_Symbol )! = POSITION_TYPE_BUY)
{
//買いポジションを開く
}
最近閉じたバーのRSI値が売られすぎのレベルの30以下である場合、それは買いシグナルを示します。
MACDなどのヒストグラムインジケータは、ゼロラインの周りで振動します。ゼロより上に上昇する値は強気トレンドを示し、ゼロより下に下降する値は弱気な価格変動を示します。ゼロに対するインディケータ値に基づいてトレーディングシグナルを作成したい場合があります。
if(macd[1] > 0 && PositionType(Symbol )! = POSITION_TYPE_BUY)
{
//買いポジションを開く
}
最近閉じたバーのMACD値が0より大きい場合、買い条件が示されます。
図17.5-MACDインジケータ
これらよりも複雑なインジケータ条件を思いつくかもしれません。しかし、ほぼすべての指標ベースの取引条件は、指標の読み取り値および/または価格の間の関係の組み合わせです。取引シグナルの複数の価格と指標条件を組み合わせるには、式の間でブールANDまたはOR演算を使用するだけです。
if(Price.Close() < bbLower && (rsi[1] < 30 || stoch[1] < signal[1])
&& PositionType(_Symbol) != POSITION_TYPE_BUY)
{
//買いポジションを開く
}
上記の式では、終値が下のボリンジャーバンドよりも低く、RSIが30未満であるか、ストキャスティクスがシグナルラインよりも低い場合、買いポジションを開きます。AND演算とOR演算を組み合わせる場合は、括弧を使用して、最初に評価される式を設定します。
インジケータのオンとオフの切り替え P234
複数のインジケータを持つEAでは、個々のインジケータをオンまたはオフにしたい場合があります。そのためには、ユーザーが必要に応じてインジケータを非アクティブ化できるようにするブール入力変数を追加する必要があります。また、オン状態とオフ状態の両方を許可するように取引条件を変更する必要があります。
例えば、ボリンジャーバンドとRSIを使用するEAを作成してみましょう。価格が下のバンドを下回り、RSIが売られすぎの領域(30未満)にある場合、買いポジションを開きます。入力変数を追加して、RSI条件のオンとオフを切り替えます。
//入力変数
input bool UseRSI = true;
//OnTick()イベントハンドラ
if(close[1] < lowerBand && ((rsi <= 30 && UseRSI == true || UseRSI == false)
&& PositionType(_Symbol) ! = POSITION_TYPE_BUY)
{
//買いポジションを開く
}
上記の例では、UserRSIという名前の入力変数を追加します。これにより、RSI取引条件がオンまたはオフになります。if演算子内で、trueとfalseの両方の状態をチェックします。UseRSI == trueの場合、rsi値が30未満かどうかを確認します。そうであれば、ほかの条件が真であれば、買いポジションも開きます。UseRSI == falseで、ほかの条件がtrueの場合、買いポジションも開きます。
括弧は、条件が評価される順序を確立します。括弧の内側のセットには操作が含まれます。(rsi <= 30 && UseRSI == true)。これが最初に評価されます。この条件がfalseの場合、外側の括弧UseRSI == false内の条件を評価します。両方の演算を分離するOR演算子( || )に注意してください。これらの条件のいずれかがtrueと評価された場合、括弧内の式全体がtrueになります。
インジケータの「オン」状態は最も内側の括弧内のセット内にあり、最初に評価されることに注意してください。インジケータの「オフ」状態は、もっとも外側の括弧のセット内にあり、OR演算子(1)によって「オン」状態から分離されます。括弧を使用してAND演算とOR演算を組み合わせて評価の順序を確立すると、複雑な取引条件を作成できます。その際、開き確固と閉じ括弧をよく見て、1つを省略したり、1つ追加しすぎたり、誤って入れ子にしたりしないようにしてください。