1. zigzagとは?
zigzagとは、次の画像のようにチャートの波動に自動でラインを引いてくれるインジケーターです。一般的にトレンドやトレンド転換点を分析するのに使います。
自分で波形を引くのが苦手な人にとって、とても有用なインジケーターです。
それとzigzagはリペイント系インジケーターとして有名です。
2. リペイント(再描写)
リペイントとは、最新足が更新され、すでに表示されているインジケーターの値を新たに書き換えることです。下記の画像で詳しく説明します。
① 最新の高値を設定され、zigzagのラインが引かれた。
② その後の相場で安値を更新せずに高値を更新した。
③ すると、前回高値へのラインは削除され、新たな高値へとラインは書き換えられる。
3. zigzagの値を取得しよう。
zigzagの値を返す関数はMT4には用意されていません。そのため、zigzagの値を取得するためには、iCustom関数を使用します。
zigzagでのiCustom関数の引数は、
iCustom(通貨ペア,時間足,”ZigZag”,Depth,Deviation,Backstep,バッファー,シフト);
となります。なので今回は、
iCustom(NULL,0,”ZigZag”,12,5,3,0,0);
これでzigzagの値を取得出来ます。この値には価格が入っています。
しかし、現時点では小数点が大きいのでNormalizeDouble関数を使って、小数点を5桁にします。
double zig = NormalizeDouble(iCustom(NULL,0,"ZigZag",12,5,3,0,0),5);
zigzagの値の返し方
zigzagの値の返し方は特殊です。天底(山と谷)以外は「0」を返します。 画像を使って解説します。
zigzagの天底以外(上記画像では線だけの部分)では全て「0」が返ってきます。
価格が0なんてあり得ませんが、zigzagの値の返し方はそう決まっています。
天底(上記画像では丸で囲った部分)のみ「0でない値」が返ってきます。
4. OnInit()で配列に初期値を格納しよう。
セットした時に一度だけ処理をするOnInit()で配列に初期値を格納していきます。
まずはグローバル変数として、2つの変数と4つの配列を定義します。
int m=0;
int n=0;
double Top[5];
double Bottom[5];
datetime t_time[5];
datetime b_time[5];
次にzigzagの値を配列に格納するため、ローソク足0~100本分の繰り返し処理で配列に値を格納する。
for(int i=0;i<=100;i++)
{
double zig = NormalizeDouble(iCustom(NULL,0,"ZigZag",12,5,3,0,i),5);
if(zig!=0 && zig==NormalizeDouble(High[i],5))
{
Top[m]=zig;
t_time[m]=Time[i];
m++;
if(m>=5)break;
}
if(zig!=0 && zig==NormalizeDouble(Low[i],5))
{
Bottom[n]=zig;
b_time[n]=Time[i];
n++;
if(n>=5)break;
}
}
9行目 Top[5]、t_time[5]の全てに値が格納されたら処理を止める。
16行目 Bottom[5]、b_time[5]の全てに値が格納されたら処理を止める。
このプログラムをそのままOnTick()に書いても普通に機能します。
しかし、ティック毎に100本分の繰り返し処理を行うのはプログラムが重くなります。
だから、必要な時だけ必要な処理をしてくれるように、OnTick()では別の書き方をします。
5. OnTick()で取得した値を配列に格納しよう。
5-1. 高値の値を配列に格納
高値(上記画像の赤丸部分)でのみ処理が起こるよう記述します。やることは2つです。
- 高値かどうかチェックする。
- リペイントであるかそうでないかチェックする。
高値かどうかチェック
if文で3つの条件式を満たすかどうか確認する。(3つとも”true”なら高値である)
if( zig!=0 &&
zig==NormalizeDouble(High[0],5) &&
zig==NormalizeDouble(iHigh(_Symbol,0,iHighest(_Symbol,0,MODE_HIGH,5,0)),5))
1行目 zigzagの値が0でない。(値が入っている)
2行目 zigzagの値が現在のローソク足の最高値と同じである。
3行目 zigzagの値がローソク足5本前までの中で最も高い価格と同じである。
上記の条件式が全て”true”なら、次の処理を実行する。
次の処理は、入った高値がリペイントであるか、そうでないかを確かめます。
リペイントであるか、そうでないかをチェック
zigzagは「高値」→「安値」→「高値」→「安値」と交互に値が入る必要があります。しかし、第2章で言ったように、リペイントすると「高値」→「高値」と連続で高値が入ってしまいます。
なので、リペイントされたのであれば「前回高値」を「今回高値」で上書きしなければなりません。
よって、入った値が、リペイントであるか、そうでないかで処理を分岐させる必要があります。
{
if( t_time[0]>b_time[0] )
{
Top[0]=zig;
t_time[0]=Time[0];
}else {
Top[3]=Top[2];
Top[2]=Top[1];
Top[1]=Top[0];
Top[0]=zig;
t_time[3]=t_time[2];
t_time[2]=t_time[1];
t_time[1]=t_time[0];
t_time[0]=Time[0];
}
}
2行目
条件式:「”t_time[0]”が”b_time[0]”より未来にある。」この条件式を噛み砕くと、「”前回高値”が”前回安値”より未来にある。」
もっと噛み砕くと・・・
「ひとつ前に入ったzigzagの値は”安値”でなく、”高値”である。」
ということは(trueなら)・・・
今回「高値」が入ると、「高値」が連続になるので、それはリペイントである。
この条件式が、”true”の場合は最新の配列だけを入れ替え、”false”の場合は配列を総入れ替え。
trueの場合(リペイントである)
4行目 zigzagの値”zig“を”Top[0]“に上書きする。
5行目 現在時間”Time[0]“を”t_time[0]“に上書きする。
false時の場合(リペイントでない)
7~9行目 “Top[]“に入ってる配列を1つずつ、ずらす。
10行目 zigzagの値”zig“を”Top[0]“に代入する。
11~13行目 “t_time[]“に入ってる配列を1つずつ、ずらす。
14行目 現在時間”Time[0]“を”t_time[0]“に代入する。
5-2. 安値の値を配列に格納
安値(下記画像の青丸部分)でのみ処理が起こるよう記述します。やることは2つです。
- 安値かどうかチェックする。
- リペイントであるかそうでないかチェックする。
安値かどうかチェック
if文で3つの条件式を満たすかどうか確認する。(3つとも”true”なら安値である)
if( zig!=0 &&
zig==NormalizeDouble(Low[0],5) &&
zig==NormalizeDouble(iLow(_Symbol,0,iLowest(_Symbol,0,MODE_LOW,5,0)),5))
1行目 zigzagの値が0でない。(値が入っている)
2行目 zigzagの値が現在のローソク足の最安値と同じである。
3行目 zigzagの値がローソク足0~5本前までの中で最も安い価格と同じである。
上記の条件式が全て”true”なら、次の処理を実行する。
次の処理は、入った安値がリペイントであるか、そうでないかを確かめます。
リペイントかどうかチェック
zigzagは「高値」→「安値」→「高値」→「安値」と交互に値が入る必要があります。しかし、第2章で言ったように、リペイントすると「安値」→「安値」と連続で安値が入ってしまいます。
なので、リペイントされたのであれば「前回安値」を「今回安値」で上書きしなければなりません。
よって、入った値が、リペイントであるか、そうでないかで処理を分岐させる必要があります。
{
if( b_time[0]>t_time[0] )
{
Bottom[0]=zig;
b_time[0]=Time[0];
}else{
Bottom[3]=Bottom[2];
Bottom[2]=Bottom[1];
Bottom[1]=Bottom[0];
Bottom[0]=zig;
b_time[3]=b_time[2];
b_time[2]=b_time[1];
b_time[1]=b_time[0];
b_time[0]=Time[0];
}
}
2行目
条件式:「”b_time[0]”が”t_time[0]”より未来にある。」この条件式を噛み砕くと、「”前回安値”が”前回高値”より未来にある。」
もっと噛み砕くと・・・
「ひとつ前に入ったzigzagの値は”高値”でなく、”安値”である。」
ということは(trueなら)・・・
今回「安値」が入ると、「安値」が連続になるので、それはリペイントである。
この条件式が、”true”の場合は最新の配列だけを入れ替え、”false”の場合は配列を総入れ替え。
trueの場合(リペイントである)
4行目 zigzagの値”zig“を”Bottom[0]“に上書きする。
5行目 現在時間”Time[0]“を”b_time[0]“に上書きする。
falseの場合(リペイントでない)
7~9行目 “Bottom[]“に入ってる配列を1つずつ、ずらす。
10行目 zigzagの値”zig“を”Bottom[0]“に代入する。
11~13行目 “b_time[]“に入ってる配列を1つずつ、ずらす。
14行目 現在時間”Time[0]“を”b_time[0]“に代入する。
6. まとめ(プログラム)
最後に、ここまでの記事の内容をまとめておきます。
OnInit()とOnTick()で書き方が違うため、少し難しく感じたかもしれませんが、してることはシンプルです。「リペイント」を理解することが出来れば、さほど難しくありません。
- zigzagの値をiCustom関数で取得する。
- OnInit()内で配列に初期値を格納しておく。
- 取得した値がリペイントであるか、そうでないかで処理を分岐し、配列に格納する。
まとめプログラムです。変数名や関数の値は自由に変更してお使い下さい。
int m=0;
int n=0;
double Top[5];
double Bottom[5];
datetime t_time[5];
datetime b_time[5];
int OnInit()
{
for(int i=0;i<=100;i++)
{
double zig = NormalizeDouble(iCustom(NULL,0,"ZigZag",12,5,3,0,i),5);
if(zig!=0 && zig==NormalizeDouble(High[i],5))
{
Top[m]=zig;
t_time[m]=Time[i];
m++;
if(m>=5)break;
}
if(zig!=0 && zig==NormalizeDouble(Low[i],5))
{
Bottom[n]=zig;
b_time[n]=Time[i];
n++;
if(n>=5)break;
}
}
Comment("Top_0= ",Top[0],"|",t_time[0],"\n",
"Top_1=",Top[1],"|",t_time[1],"\n",
"Top_2=",Top[2],"|",t_time[2],"\n",
"Bottom_0=",Bottom[0],"|",b_time[0],"\n",
"Bottom_1=",Bottom[1],"|",b_time[1],"\n",
"Bottom_2=",Bottom[2],"|",b_time[2],"\n");
return(INIT_SUCCEEDED);
}
void OnTick()
{
double zig = NormalizeDouble(iCustom(NULL,0,"ZigZag",12,5,3,0,0),5); //zigzagの値取得
if( zig!=0 &&
zig==NormalizeDouble(High[0],5) &&
zig==NormalizeDouble(iHigh(_Symbol,0,iHighest(_Symbol,0,MODE_HIGH,5,0)),5))
{
if( t_time[0]>b_time[0] ){
Top[0]=zig;
t_time[0]=Time[0];
}else {
Top[3]=Top[2];
Top[2]=Top[1];
Top[1]=Top[0];
Top[0]=zig;
t_time[3]=t_time[2];
t_time[2]=t_time[1];
t_time[1]=t_time[0];
t_time[0]=Time[0];
}
}
if( zig!=0 &&
zig==NormalizeDouble(Low[0],5) &&
zig==NormalizeDouble(iLow(_Symbol,0,iLowest(_Symbol,0,MODE_LOW,5,0)),5))
{
if( b_time[0]>t_time[0] ){
Bottom[0]=zig;
b_time[0]=Time[0];
}else{
Bottom[3]=Bottom[2];
Bottom[2]=Bottom[1];
Bottom[1]=Bottom[0];
Bottom[0]=zig;
b_time[3]=b_time[2];
b_time[2]=b_time[1];
b_time[1]=b_time[0];
b_time[0]=Time[0];
}
}
Comment("Top_0= ",Top[0],"|",t_time[0],"\n",
"Top_1=",Top[1],"|",t_time[1],"\n",
"Top_2=",Top[2],"|",t_time[2],"\n",
"Bottom_0=",Bottom[0],"|",b_time[0],"\n",
"Bottom_1=",Bottom[1],"|",b_time[1],"\n",
"Bottom_2=",Bottom[2],"|",b_time[2],"\n");
}