セットアップ
必要なもの:
- 1つのジグザグプロット
- 高値と安値のためのデータバッファ2つ
- 入力パラメータ
- インジケーターが再計算されるたびにリセットされるシステム変数のセット
次に、コードの基本部分を見てみましょう:
#property indicator_buffers 2 #property indicator_plots 1 input double retracement=23.6; // リトレースメントの割合 input double minSizeInAtrUnits=0.0; // ATR単位での波の最小サイズ input int rollingAtrPeriod=14; // ローリングATR期間 input color Color=clrDodgerBlue; // 波の色 input int Width=3; // 波の幅 input ENUM_LINE_STYLE Style=STYLE_SOLID; // 波のスタイル //--- アップウェーブとダウンウェーブの配列 double upWaves[], dwWaves[];
upWaves配列は高値を、dwWaves配列は安値を格納します。
システム変数について:
最後の波のタイプ、開始位置、終了位置、開始と終了からのバーの距離を把握する必要があります。
さらに、局所的な高値と低値の変数、各ポイントからのバーの距離も必要です。
//--- ジグザグの追跡 int wave_type=0; // 波のタイプ [0] なし [1] 上昇 [2] 下降 double wave_start_price=0.0; // 波の開始価格 double wave_end_price=0.0; // 波の終了価格 int wave_start_distance=0; // 開始価格からのバーの距離 int wave_end_distance=0; // 終了価格からのバーの距離 //--- 高値の追跡 double high_mem=0.0; int distance_from_high=0; //--- 低値の追跡 double low_mem=0.0; int distance_from_low=0; //--- ローリングATR double rollingAtr=0.0; int rollingAtrs=0;
これでローリングATRの単位と計算された数値が準備できました。
次に、システムリセット関数を作成します:
void resetSystem() {
ArrayFill(upWaves, 0, ArraySize(upWaves), 0.0);
ArrayFill(dwWaves, 0, ArraySize(dwWaves), 0.0);
wave_type=0;
wavestart_price=0.0;
wavend_price=0.0;
wavestart_distance=0;
wavend_distance=0;
high_mem=0.0;
low_mem=0.0;
distance_from_high=0;
distance_from_low=0;
rollingAtr=0.0;
rollingAtrs=0;
} 標準的な処理で、配列をゼロで埋め、システム変数をリセットします。
OnInitでは、バッファを設定し、プロットを作成し、初めてリセットを呼び出します:
SetIndexBuffer(0, upWaves, INDICATOR_DATA); SetIndexBuffer(1, dwWaves, INDICATOR_DATA); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0); PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_ZIGZAG); PlotIndexSetInteger(0, PLOT_LINE_COLOR, 0, Color); PlotIndexSetInteger(0, PLOT_LINE_WIDTH, Width); PlotIndexSetInteger(0, PLOT_LINE_STYLE, Style); resetSystem();
では、計算に進みましょう。
最初に処理するのはローリングATRです。このATR期間を超えるバーが集まるまで、他のことは何もしません。
ローリングATRを管理する部分は次の通りです:
- 期間を超えるまで、見つかったバーの範囲を合計に追加し続ける
- 期間に到達したら、最初の割り算(平均)を行う
- その後、ローリングATRから古い部分をクリップし、新しい部分を追加します
//--- ATRを管理する
rollingAtrs++;
if(rollingAtrs > rollingAtrPeriod) {
double new_portion = ((high[i] - low[i]) / _Point) / ((double)rollingAtrPeriod);
//--- 古い部分を削除し、新しい部分を追加
rollingAtr = (rollingAtr) - (rollingAtr / ((double)rollingAtrPeriod)) + new_portion;
}
else if(rollingAtrs <= rollingAtrPeriod) {
rollingAtr += (high[i] - low[i]) / _Point;
if(rollingAtrs == rollingAtrPeriod) {
rollingAtr /= ((double)rollingAtrs);
//--- 高値と低値のメモリを開始
high_mem = high[i];
low_mem = low[i];
distance_from_high = 0;
distance_from_low = 0;
}
} 素晴らしいですね!次の課題があります。
このジグザグの基盤はリトレースメントです。ただし、リトレースメントが発生するには、少なくとも1つの波が必要です。
最初の波は何をリトレースするのでしょうか?笑
そのため、次のようにします:
- ATRが充填されたら(ATRが期間に達したら)、システム変数に高値と安値を格納します。
- どちらの側がATR単位の有効なサイズを持つ波を形成し、新しい高値(アップウェーブ)または新しい安値(ダウンウェーブ)を形成するかが勝ちます。
このようにして、初期波のリトレースメントを持たずに、シーケンスを開始する必要があります。
ここでの実装は次の通りです:
//--- 波のタイプがまだない場合
else {
//--- 高値を超え、安値は超えない場合
if(high[i] > high_mem && low[i] >= low_mem) {
double new_wave_size_in_atr_units = ((high[i] - low_mem) / _Point) / rollingAtr;
//--- 新しい波のサイズが有効であれば
if(new_wave_size_in_atr_units >= minSizeInAtrUnits) {
//--- 新しいアップウェーブを開始
wave_type = 1;
wave_start_price = low_mem;
wave_start_distance = distance_from_low;
wave_end_price = high[i];
wave_end_distance = 0;
dwWaves[i - wave_start_distance] = low_mem;
upWaves[i] = high[i];
high_mem = high[i];
distance_from_high = 0;
low_mem = low[i];
distance_from_low = 0;
}
}
//--- 安値を下回り、高値は超えない場合
else if(low[i] < low_mem && high[i] <= high_mem) {
double new_wave_size_in_atr_units = ((high_mem - low[i]) / _Point) / rollingAtr;
//--- 新しい波のサイズが有効であれば
if(new_wave_size_in_atr_units >= minSizeInAtrUnits) {
//--- 新しいダウンウェーブを開始
wave_type = -1;
wave_start_price = high_mem;
wave_start_distance = distance_from_high;
wave_end_price = low[i];
wave_end_distance = 0;
upWaves[i - wave_start_distance] = high_mem;
dwWaves[i] = low[i];
high_mem = high[i];
distance_from_high = 0;
low_mem = low[i];
distance_from_low = 0;
}
}
//--- 両方を超えた場合
else if(low[i] < low_mem && high[i] > high_mem) {
high_mem = high[i];
low_mem = low[i];
distance_from_high = 0;
distance_from_low = 0;
}
} 素晴らしい!最後の部分です。
- アップウェーブの場合:
- 新しい高値が作成されると、前の高値から新しい高値の位置にジグザグを移動します。この際、バーの距離を保持しているので可能です。また、安値と安値からの距離を更新します。これにより、ピークからの最安値をキャッチし、その後に十分にリトレースするか確認します。
- 新しい安値が作成された場合、または新しい安値が設定された場合、ピークから安値までの距離を計算し、波のサイズで割ります。そして、入力パラメータのスケールに合わせるために100を掛けます。もし波のサイズが100ポイント、リトレースメントが24ポイントであれば、24/100=0.24、次に×100=24%となります。新しい「仮想的な」波が以前のものをリトレースする際もATR単位に対して有効であれば新しいダウンウェーブを開始し、局所的な高値と安値を設定し、バーの距離を設定します。
関連するコードは以下の通りです:
//--- アップウェーブがある場合
if(wave_type == 1) {
//--- 波が上に拡大した場合
if(high[i] > wave_end_price) {
//--- 配列位置から前の終了価格を削除(0.0=空)
upWaves[i - wave_end_distance] = 0.0;
//--- 新しい位置に配置
upWaves[i] = high[i];
wave_end_price = high[i];
wave_end_distance = 0;
high_mem = high[i];
distance_from_high = 0;
low_mem = low[i];
distance_from_low = 0;
}
//--- リトレースメントを確認
if(low[i] < low_mem || distance_from_low == 0) {
low_mem = low[i];
distance_from_low = 0;
double size_of_wave = (wave_end_price - wave_start_price) / _Point;
double size_of_retracement = (wave_end_price - low_mem) / _Point;
if(size_of_wave > 0.0) {
double retraced = (size_of_retracement / size_of_wave) * 100.0;
double new_wave_size_in_atr_units = ((wave_end_price - low_mem) / _Point) / rollingAtr;
//--- 新しい波のサイズが有効であれば
if(new_wave_size_in_atr_units >= minSizeInAtrUnits) {
//--- リトレースメントが重要であれば、新しいダウンウェーブを開始
if(retraced >= retracement) {
wave_type = -1;
wave_start_price = high[i - distance_from_high];
wave_start_distance = distance_from_high;
wave_end_price = low[i];
wave_end_distance = 0;
upWaves[i - wave_start_distance] = high_mem;
dwWaves[i] = low[i];
high_mem = high[i];
distance_from_high = 0;
low_mem = low[i];
distance_from_low = 0;
}
}
}
}
} ダウンウェーブの場合も同様の処理を行います。
これで、リトレースメントジグザグが完成しました!
こちらが23.6%のリトレースメントとATR単位での最小波サイズ0.0のジグザグです:

そして、こちらがATR単位での最小波サイズ3の同じジグザグです:

これで、素晴らしいトレーディングを楽しんでください!
コメント 0