インジケータ1

#property strict を使用したインジケータの試作について

これは「さかたつとむML」のNO.100からNO.108に掲載された記事に修正を加えたものです。


カスタムインジケータ 1

 今回からインジケータを作ります。
最小作業、最小アイテム、最小アルゴリズムに分けて見ていきます。


最小作業

プログラムファイルの新規作成

1、Meta Editorの新規作成をクリックしMQL Wizardを表示します。
カスタムカスタムインジケータを選択します。「次へ」をクリックします。
2、名前、著作者、リンク、パラメータ等の必要事項を記入し、「次へ」をクリックします。
3、カスタムカスタムインジケータのイベントハンドラを選択します。
4、現在、OnCalculate(...,prices)の方はまだ使用できません。
5、最小アイテムではOnCalculate(...,open,high,low,close)だけ選択します。「次へ」をクリックします。
6、次の画面では描画プロパティを選択します。
チャートに表示する場合はチェックは不要です。何もしないで「完了」を押します。
サブウインドウを使うときはここをチェックします。

これで先ほど入力した名前の基本的なプログラムファイルが出来上がります。
メニュ>ファイル>上書き保存をクリックすると保存されます。

以下のファイルが作成されます。

//+-----------------------------------------+
//| test26.mq4 |
//| Copyright 2015, T.S. |
//| http:// |
//+-----------------------------------------+
#property copyright "Copyright 2015, T.S."
#property link "http://"
#property version "1.00"
#property strict
#property indicator_chart_window
//+-------------------------------------------+
//| Custom indicator initialization function 
//+-------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping

//---
return(INIT_SUCCEEDED);
}
//+-------------------------------------------+
//| Custom indicator iteration function 
//+-------------------------------------------+
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[])
{
//---

//--- return value of prev_calculated for next call
return(rates_total);
}
//+--------------------------------------------+

これは新しいmql4言語を使うためのテンプレート(ひな型)です。
もし古いmql4言語を使うのであれば、上記コードを全部消してから、
下記のように書き直す必要があります。

//+--------------------------------------------+
#property copyright "Copyright 2015, T.S."
#property link "http://"
#property version "1.00"
#property indicator_chart_window
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int init()
{

return(0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int deinit()
{

return(0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int start()
{

}
//+--------------------------------------------+

上記の場合いずれも
1、
#property indicator_chart_window
あるいは
2、
#property indicator_separate__window
のどちらかを選択します。

通貨ペア時間足の表示する画面にインジケータを表示したい時は1、を選びます。
通貨ペア時間足の表示する画面の下のサブウインドウに表示したい時は2、を選びます。

 古い言語、新しい言語、strictのある新しい言語と、
アップグレードされたmql4では、3通りのプログラミングの仕方があります。
ここではstrictプロパティのあるプログラミングになります。

新規作成でのテンプレートでは、

#property strict

が表示されていますが、
削除しても新しいmql4言語でのプログラムは作成出来ます。

strictプロパティは、新しい言語の変更の数が多くなったため、
最大互換性を提供するための事前アプローチとして導入されています。

 参考のため他に変わった点を列挙しますと以下のようになります。

以前のMQL4では、上記関数は任意のパラメータと、任意のタイプの戻り値を持つことが出来ましたが、
新しいMQL4では、前もって定義された、パラメータセットと、戻り値タイプを持つ必要があります。

構造体、クラス、オブジェクトポインタ、voidタイプ、thisキーワードが追加。

隠蔽、タイプ拡張性、継承、多態性、オーバーロード、仮想関数が追加。

char, short, long, uchar, ushort, uint, ulongの整数タイプが追加。
doubleのデータタイプが追加。
Stringは、以前のANSI(シングルバイト1つ)フォーマットに変わり、
Unicodeフォーマットで提供。

演算子の優先順位は標準C言語に一致。

新しいMQL4バージョンでは、ifコンデションは論理的なチェックに変更。

ArrayCopyRates()関数の動作が変更。

FileWrite()、 FileWriteArray()、 FileWriteDouble()、FileWriteInteger() 、 FileWriteString()関数は、
戻り値がintからuintタイプへ変更されました。


カスタムインジケータ 2

 今回は最小アイテムです。
最小アイテムはさらに次のように分けます。
1.セット(集合)アイテム
2.インテグレーション(統合)アイテム
3.ソリューションアイテム

+++++++++++++++++++++++++++
1.セットアイテム

#property indicator_buffers 
チャートに表示するインジケータに必要なバッファの数を指定

IndicatorBuffers(1);
IndicatorBuffers()ではインジケータと、
カスタムインジケータの計算に使用するバッファの
全合計を指定します。
ここでは過不足なくセットします。
(詳しくはMQL5リファレンスを参照してください。
カスタム指標、指標スタイルの例)
-------------------------------

#property indicator_color
インジケータの色を指定します。
未設定のときは黒色がデフォルトになります。
インジケータが1コのときは

indicator_color1  Silver
となります。

indicator_colorN
では、Nは表示インジケータの番号です。
Nは1から始まります。
グラフィック表示インジケータのライン番号の色(Web Colors)を
表します。

Web Colorsの例は以下にようになります。
clrRed 赤
clrBlue 青
clrYellow 黄
clrGreen 緑
-------------------------------

IndicatorDigits();
インジケータの小数点以下の桁数を表します。

IndicatorDigits(Digits);
となっているとき、
Digitsは
チャートに表示された通貨ペアの価格の小数点以下桁数です。
これも過不足なくセットします。

+++++++++++++++++++++++++++
2.インテグレーションアイテム
 SetIndexBuffer()
doubleタイプの1次元動的配列表示インジケータバッファをバインドします。

この関数には2つのタイプがあります。

bool SetIndexBuffer(
int index, 
double buffer[] 
);

index 
表示インジケータのindexを指定します。

buffer[] 
表示インジケータの1次元動的配列を設定します。
-------------------------------

bool SetIndexBuffer(
int index,
double buffer[],
ENUM_INDEXBUFFER_TYPE data_type 
);

index 
表示インジケータのindexを指定します。

buffer[] 
表示インジケータの1次元動的配列を設定します。

ENUM_INDEXBUFFER_TYPE data_type 
INDICATOR_DATA = 0
INDICATOR_COLOR_INDEX = 1
INDICATOR_CALCULATIONS = 2

SetIndexBuffer() 関数を使用し、
標識バッファーとして指定される配列のそれぞれに格納される
次のデータ型を指定します。

INDICATOR_DATA
描写するデータバッファとして使用するとき。

INDICATOR_COLOR_INDEX
Drawing StylesのENUM_DRAW_TYPEで、
以下のCOLOR_INDEXのインジケータを使用するときに指定します。

DRAW_COLOR_LINE
DRAW_COLOR_SECTION
DRAW_COLOR_HISTOGRAM
DRAW_COLOR_HISTOGRAM2
DRAW_COLOR_ARROW
DRAW_COLOR_ZIGZAG
DRAW_COLOR_ZIGZAG
DRAW_COLOR_BARS
DRAW_COLOR_CANDLES

INDICATOR_CALCULATIONS
中間計算のための補助バッファとして使用するとき。


計算あるいはグラフィック表示のタイプを理解し、
個々のニーズに合わせる必要があります。
------------------------------- 

SetIndexStyle(0,DRAW_LINE,STYLE_DOT);
バインドされた表示インジケータのタイプ、スタイル、幅、色を指定します。

void SetIndexStyle(
int index, // line index
int type, // line type
int style=EMPTY, // line style
int width=EMPTY, // line width
color clr=clrNONE // line color
);
-------------------------------


double mBuffer[];
動的配列のバッファを定義します。


+++++++++++++++++++++++++++
3.ソリューションアイテム
 今回は小さなターゲットとして
単純移動平均線iMA()を使用します。

iMA(NULL,0,mPeriod,0,MODE_SMA,PRICE_CLOSE,i);

double iMA(
string symbol, 
int timeframe,
int ma_period,
int ma_shift,
int ma_method, // averaging method
int applied_price, // applied price
int shift // shift
);

symbol:チャートの通貨ペア名:NULLは使用チャート通貨ペア
timeframe:チャートの時間足:0は使用チャートの時間足
ma_period:移動平均線の期間
ma_shift:移動平均線のシフト期間
ma_method:移動平均線のメソッド:MODE_SMAは単純移動平均線
applied_price:移動平均で使用する価格データ:PRICE_CLOSEは終値
shift:バーの位置:

input int mPeriod=200;
グランビルの法則で使用されている200日移動平均線を作成。


カスタムインジケータ 3

最小アルゴリズム

 今回はインジケータの中でも一番小さなアルゴリズムです。
全体を3つに分けて説明しますが、始にプログラムの全コードを記述します。

#property copyright "Copyright 2015, T.S."
#property link "http://"
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Silver

input int mPeriod=200;

double mBuffer[];
//-----------------

void OnInit(void)
{
IndicatorBuffers(1);
IndicatorDigits(Digits);
SetIndexStyle(0,DRAW_LINE,STYLE_SOLID);

//(1)
bool x=ArrayGetAsSeries(mBuffer);

SetIndexBuffer(0,mBuffer);

bool y=ArrayGetAsSeries(mBuffer); 
Print("before = ",x);
Print("after = ",y);

}
//-----------------

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[])
{
int limit=rates_total-prev_calculated;
//---
if(rates_total<=mPeriod) return(0);
//---
if(prev_calculated>0) limit++;

for(int i=0; i {

mBuffer[i]=iMA(NULL,0,mPeriod,0,MODE_EMA,PRICE_CLOSE,i);
}
//---
//(2)
int bars=Bars(Symbol(),0);
Print("Bars = ",bars,", rates_total = ",rates_total,", prev_calculated = ",prev_calculated);
Print("time[0] = ",time[0]," time[rates_total-1] = ",time[rates_total-1]);
//---
return(rates_total);
}
//+------------------------------------------------------------------+

 プログラムを順に説明していきます。
以下のコードはvoid OnInit(void)の前に記述します。

#property copyright "Copyright 2015, T.S."
#property link "http://"
#property version "1.00"
#property strict
//#property strictは省略しても動作します。
#property indicator_chart_window
//あるいは#property indicator_separate_windowを選択します。
#property indicator_buffers 1
//表示するインジケータの数を表しています。
#property indicator_color1 Silver
//表示するインジケータの色はシルバーです。
input int mPeriod=200;
//表示するインジケータの期間です。
double mBuffer[];
//使用する動的配列の宣言です。

----------------------------------------
 次は初期化関数OnInit()の内部です。

void OnInit(void)
{
IndicatorBuffers(1);
IndicatorDigits(Digits);
SetIndexStyle(0,DRAW_LINE,STYLE_SOLID);
SetIndexBuffer(0,mBuffer);
//上記は前回説明したので省略。

その下は
//(1)
//before
SetIndexBuffer(0,mBuffer);
//after

}
ですが、
//(1)の
SetIndexBuffer(0,mBuffer)では
配列から時系列へ変わります。
それを解りやすくするため
//(1)
//before
//after
に次のような関数を置きます。

//beforeには
bool x=ArrayGetAsSeries(mBuffer);

// after には
bool y=ArrayGetAsSeries(mBuffer);
Print("before = ",x);
Print("after = ",y);

コードを追加しコンパイルした後、
プログラムをチャートにアタッチすると、
エキスパートタブには、
//beforeにはfalse
//after にはtrue
を表示します。


falseは、mBufferが配列
trueは、mBufferが時系列を意味しています。

つまり、SetIndexBuffer(0,mBuffer)は、
mBufferをチャートのインジケータにバインドする他に、
mBufferを配列から時系列へ変更されたことになります。

-------------------------
 次はOnCalculate()です。
アップグレードMQL4では、
インジケータは以下のタイプのみしか使用されません。

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[])
{

return(rates_total);
}

新しいMQL4では、
前もって定義されたパラメータセットと、戻り値のタイプを持つ必要があります。

rates_total
rates_totaはチャートに表示可能なバーの総数を表しています。

prev_calculated
prev_calculatedはOnCalculate() ですでに計算されたバーの数を表しています。

datetime &time[]
double &open[]
double &high[]
double &low[]
double &close[]
long &tick_volume[]
long &volume[]
int &spread[]
//以上は説明するまでもないので省略します。

次はOnCalculate(){...}の内部のコードです。

int limit=rates_total-prev_calculated;
この計算は、
まだ計算が済んでいないバーの数になります。


if(rates_total<=mPeriod) return(0);
ここでの計算は、ifコンデションにより
移動平均値の期間よりrates_totalが小さいときは戻り値は0を返します。

if(prev_calculated>0) limit++;
この計算では、
バーの数が1つ以上計算が済んだときは、
limit(まだ計算が済んでいないバーの数)に+1を加えます。

//(B)
for(int i=0; i {

mBuffer[i]=iMA(NULL,0,mPeriod,0,MODE_EMA,PRICE_CLOSE,i);
}
上の式//(B)では

(1)
すでに今表示している一番新しいバーまで計算が済んでいると、
int limit=rates_total-prev_calculated;
ではlimitは0
if(prev_calculated>0) limit++;
ではlimitは+1です。
したがってiは0になり
//(B)の
mBuffer[i]はmBuffer[0]の計算をすることになります。
ここでは各tickごとに毎回計算します。

(2)
すでに今表示している一番新しいバーの一つ前まで計算が済んでいるとすると、
int limit=rates_total-prev_calculated;
ではlimitは+1
if(prev_calculated>0) limit++;
ではlimitは+2です。
したがってiは0と1になり
//(B)の
mBuffer[i]はmBuffer[0]とmBuffer[1]の計算をすることになります。

(3)
すでに今表示している一番新しいバーのn個前まで計算が済んでいるとすると、
int limit=rates_total-prev_calculated;
ではlimitは+n
if(prev_calculated>0) limit++;
ではlimitは (n+1)です。
したがってiは0、1、…、nになり
//(B)の
mBuffer[i]はmBuffer[0]、mBuffer[1]、…、mBuffer[n]の計算をすることになります。

解り易くするため計算の順序を逆に記述しましたが、
実際はprev_calculatedは0から大きくなっていきますので、
limiはの大きい数から小さい数へ推移します。

それを理解しやすくするためのコードを、
プログラムの終わりの方に、
下の//(B)で追加してあります。
エキスパートタブにその結果が表示されます。

//(B)

int bars=Bars(Symbol(),0);

Print("Bars = ",bars,", rates_total = ",rates_total
,", prev_calculated = ",prev_calculated);

Print("time[0] = ",time[0]," time[rates_total-1] = "
,time[rates_total-1]);



カスタムインジケータ 4

最小アルゴリズム

 次はOnCalculate()です。
アップグレードMQL4では、
インジケータは今のところ以下のタイプのみしか使用出来ません。

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[])


return(rates_total);
}

以前にも書きましたが、
新しいMQL4では前もって定義されたパラメータセットと、
戻り値のタイプを持つ必要があります。

定義されたパラメータセットは以下のようになります。

rates_total
rates_totaはチャートに表示可能なバーの総数を表しています。

prev_calculated
prev_calculatedはOnCalculate() ですでに計算されたバーの数を表しています。

datetime &time[]
double &open[]
double &high[]
double &low[]
double &close[]
long &tick_volume[]
long &volume[]
int &spread[]

戻り値は以下になります。

return(rates_total);

----------------------------------------
 次はOnCalculate(){...}の内部のコードです。

int limit=rates_total-prev_calculated;

この式はまだ計算が済んでいないバーの数の計算になります。


if(rates_total<=mPeriod) return(0);

ここでの計算は、ifコンデションにより
移動平均値の期間よりrates_totalが小さいときは戻り値は0を返します。

if(prev_calculated>0) limit++;

この計算では、
バーの数が1つ以上計算が済んだときは、
limit(まだ計算が済んでいないバーの数)に+1を加えます。

次の式
//(B)
for(int i=0; i {

mBuffer[i]=iMA(NULL,0,mPeriod,0,MODE_EMA,PRICE_CLOSE,i);
}
では、

(1)
すでに今表示している一番新しいバーまで計算が済んでいると、
int limit=rates_total-prev_calculated;では
limitは0
if(prev_calculated>0) limit++;では
limitは+1です。
したがってiは0になり
//(B)の
mBuffer[i]はmBuffer[0]の計算をすることになります。
ここでは各tickごとに毎回計算します。

(2)
すでに今表示している一番新しいバーの一つ前まで計算が済んでいるとすると、
int limit=rates_total-prev_calculated;では
limitは+1
if(prev_calculated>0) limit++;では
limitは+2です。
したがってiは0と1になり
//(B)の
mBuffer[i]はmBuffer[0]とmBuffer[1]の計算をすることになります。

(3)
すでに今表示している一番新しいバーのn個前まで計算が済んでいるとすると、
int limit=rates_total-prev_calculated;では
limitは+n
if(prev_calculated>0) limit++;では
limitは (n+1)です。
したがってiは0、1、…、nになり
//(B)の
mBuffer[i]はmBuffer[0]、mBuffer[1]、…、mBuffer[n]の計算をすることになります。

解り易くするため計算の順序を逆に記述しましたが、
実際はprev_calculatedは0から大きくなりますので、
limitは大きい数から小さい数へ推移します。

それを理解しやすくするため、
プログラムの終わりの方に、
下の//(B)でコードを追加してあります。
//(B)
int bars=Bars(Symbol(),0);

Print("Bars = ",bars,", rates_total = ",rates_total,", prev_calculated = ",prev_calculated);

Print("time[0] = ",time[0]," time[rates_total-1] = ",time[rates_total-1]);

その結果はエキスパートタブに表示されます。




カスタムインデイケータ 5

最小インデイケータ2

 前回までは組み込みテクニカル指標関数のiMAを使って、
インデイケータを作りました。
テクニカル指標関数は他に36(icustom含む)も用意されていいるので、
ほとんどはこれで間に合いますが、
自分で作りたい時もあります。
そんな時のため、
今回はテクニカル指標関数を使わない
カスタムインデイケータを作っていきたいと思います。



始にインデイケータのプログラムテキストを新規作成します。

1、Meta Editorの新規作成をクリックし、MQLWizardを表示します。
カスタムカスタムインデイケータを選択し、「次へ」をクリックします。
2、名前、著作者、リンク、パラメータ等の必要事項を記入し、「次へ」をクリックします。
3、カスタムカスタムインデイケータのイベントハンドラを選択します。
4、OnCalculate(...,open,high,low,close)だけ選択します。「次へ」をクリックします。
5、次の画面では描画プロパティを選択します。
チャートに表示する場合はチェックは不要です。何もしないで「完了」を押します。
サブウインドウを使うときはここをチェックします。
*注意:現在、OnCalculate(...,prices)の方はまだ使用できません。


これで先ほど入力した名前のプログラムテキストが表示されます。
メニュ>ファイル>上書き保存をクリックし保存します。

テキストには、
#property strict

が表示されていますが、
削除しても新しいmql4言語でのプログラムは作成出来ます。


 前回使用アイテムのセットアイテム、インテグレーションアイテム、
ソリューションアイテムにそれぞれ追加していきます。

1.セットアイテム
#property indicator_buffers 
#property indicator_color
IndicatorBuffers(1);
IndicatorDigits();

2.インテグレーションアイテム
SetIndexBuffer();
SetIndexStyle(0,DRAW_LINE,STYLE_DOT);
double mBuffer[];


3.ソリューションアイテム
iMA(NULL,0,mPeriod,0,MODE_SMA,PRICE_CLOSE,i);
input int mPeriod=200;


 今回は次のようなアイテムを追加します。

1.セットアイテム
SetIndexDrawBegin(0,draw_begin);

2.インテグレーションアイテム
ArraySetAsSeries();
ArrayInitialize();

3.ソリューションアイテム
iMA(NULL,0,mPeriod,0,MODE_SMA,PRICE_CLOSE,i);はなくなります。
代わりに下のアイテムが増えます。
close[];
IsStopped();

 順を追って説明していきます。

1.セットアイテム
int draw_begin=mPeriod-1;
下の関数のdraw_begin変数を定義。

SetIndexDrawBegin(0,draw_begin);
インジケータラインの、データが始まるバーの番号をセット。
インジケータは0から7まで使用できます。

void SetIndexDrawBegin( 
int index, // ラインインデックス 
int begin // ポジション
);
戻り値はなし。

インジケータは左から右に描かれます。
デフォルトでは0がセットされます。

2.インテグレーションアイテム
ArraySetAsSeries();
選択された動的配列へ AS_SERIESをセットする関数です。
bool ArraySetAsSeries( 
const void& array[], // 参照配列
bool flag // true はインデックスの順番の反転を意味 
);
成功すると戻り値はtrueを返します。

AS_SERIESフラグは多次元配列、static配列はセットできません。
時系列配列のインデックスは配列と異なり、
時系列配列の要素は新しいデータから古いデータへ、
終わりから始まりに向かいインデックスされます。

ArrayInitialize();
予め定められた値により数的配列を初期化する関数です。
タイプはchar、short、int、long、float、double、uint です。
戻り値はなし。


3.ソリューションアイテム
close[];
OnCaluculate()のconst、参照渡しの引数で、
バーの終値の時系列配列です。

IsStopped();
mql4プログラムの強制的シャットダウンをチェックします。
もし_StopFlag システム変数が0以外の値を含むなら戻り値はtrueです。
mql4プログラムが操作を完了させる命令のとき、_StopFlagには0でない値が書き込まれます。
この時はすぐにプログラムを終了しますが、
そうでない時はプログラムは3秒後に外部から強制的に終了します。