フィボナッチ・ジグザグ:MetaTrader 5向けインジケーターの設定ガイド

Mike 2025.03.03 08:57 21 0 0
添付ファイル

セットアップ

必要なもの:

  • 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;
 }
}

素晴らしい!最後の部分です。

  • アップウェーブの場合:
  1. 新しい高値が作成されると、前の高値から新しい高値の位置にジグザグを移動します。この際、バーの距離を保持しているので可能です。また、安値と安値からの距離を更新します。これにより、ピークからの最安値をキャッチし、その後に十分にリトレースするか確認します。
  2. 新しい安値が作成された場合、または新しい安値が設定された場合、ピークから安値までの距離を計算し、波のサイズで割ります。そして、入力パラメータのスケールに合わせるために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