English Deutsch
preview
MQL5入門(第14回):初心者のためのカスタムインジケーター作成ガイド(III)

MQL5入門(第14回):初心者のためのカスタムインジケーター作成ガイド(III)

MetaTrader 5トレーディングシステム |
135 6
Israel Pelumi Abioye
Israel Pelumi Abioye

はじめに

再びお読みいただきありがとうございます。これまでの記事では、バッファとプロットを使って、MQL5でカスタムインジケーターを構築する方法を学んできました。バッファはインジケーターの値を保存するために使われ、プロットはそれらの値をチャート上に視覚的に表示するために使われます。これらの方法は多くのインジケーターにとって有効ですが、より複雑なビジュアル表現を必要とする場合には限界があります。

今回の記事では、新たなアプローチとして、MetaTrader 5のチャートオブジェクトを使ってインジケーターを構築する方法を紹介します。チャートオブジェクトはラベルや図形、トレンドラインなどをチャート上に直接描画できるため、より柔軟なインジケーター作成が可能になります。この技術は、パターンを示したり、重要な価格水準を視覚的に表したりするような、ユニークなグラフィカル要素を必要とするインジケーターの開発に適しています。

今回は、ハーモニックパターン風のインジケーターを作成しながら学習を進めていきます。特定のパターン(ガートレー、バット、バタフライなど)に焦点を当てるのではなく、どのようにしてチャートオブジェクトを用いてインジケーターを構築できるのかに注目します。ハーモニックパターンの検出ロジックは汎用化されており、必要に応じて様々なパターンに対応できる設計です。 なお、本連載第9回では、MQL5におけるトレンドラインや四角形、ラベルなどのオブジェクトの使い方について学習しました。今回はその応用として、それらを活用してインジケーターを作成する方法を実践していきます。この記事を読み終えるころには、チャートオブジェクトを動的に操作して独自の視覚的インジケーションを開発する手法をしっかりと理解できるようになるでしょう。

この記事では、次の内容を学びます。

  • MetaTrader 5チャートオブジェクトを使ったカスタムインジケーターの作成方法(バッファやプロットは使用しません)
  • ハーモニックパターンの構造と、プライスアクションにおける識別方法
  • ハーモニックパターンを形成するための市場における重要なスイングポイントの検出方法
  • パターン形成の検証に使用するフィボナッチリトレースメントの活用法
  • 三角形やラインなどの図形をプログラムで描画し、チャート上にパターンを可視化する方法
  • 無効なパターンをフィルタリングし、シグナルの精度を向上させる方法

1. ハーモニックパターンインジケーター

1.1. ハーモニックパターンインジケーターの理解

ハーモニックパターンとは、特定のフィボナッチ比率を用いて市場の反転ゾーンを特定するための価格構造です。ガートレー、バット、バタフライなどのパターンは、価格の動きによって形成される幾何学的な形状に基づき、高い確率での取引チャンスを示します。

ハーモニックパターンは、重要な価格ポイントの識別とフィボナッチ比率による構造の検証が必要になるため、RSIや移動平均線のような標準的なインジケーターと異なり、バッファーやプロットだけでは簡単に扱えないという特徴があります。そのため、視覚的に分かりやすく表示するには、より複雑なロジックとアプローチが必要です。

今回の記事では、特定のパターン(たとえば、ガートレイやバット、バタフライなど)に焦点を当てるのではなく、MQL5のチャートオブジェクトを使ってインジケーターを開発する方法に重点を置いて学習します。ハーモニックパターンの検出ロジックは汎用化されており、必要に応じて様々なパターンに対応できる設計です。

これをおこなうために、チャート上に重要なスイングポイント(高値と安値)をマークし、テキストオブジェクト(XABCD)を使って重要な水準を示し、さまざまなオブジェクトを用いてパターン構造を描写し、フィボナッチレベルを適用してパターンの精度と妥当性を高めます。

1.2. プロジェクトの設定

私がよく言うように、インジケーターを設計する前に、まずどのように表示されるべきかを明確に思い描くことが重要です。インジケーターがどのように構成されるべきかを正確に把握しておくことで、開発プロセスがスムーズになり、最終的な成果物が要件を満たすことが保証されます。

このプロジェクトでは、MetaTrader 5 のチャートオブジェクトを使用して、ブル(上昇)およびベア(下降)のハーモニックパターンの両方を構築します。インジケーターは、複数のグラフィカル要素を描画してパターンの構造を形成し、重要なスイングポイントを特定し、それらをテキストオブジェクト(XABCD)でマークし、パターンの見栄えを良くするためにフィボナッチレベルも追加します。

ハーモニックパターンに近いインジケーターを作成するだけでなく、この方法を通じてMQL5のチャートオブジェクトを実際に扱う経験を得ることができ、今後のカスタムインジケーター開発にも有用なスキルとなります。チャートオブジェクトを使ってこれらのパターンを作成する方法を解説するだけでなく、発生し得る問題点についても取り上げます。たとえば、オブジェクトの位置ずれ、フィボナッチレベルの誤配置、スイングポイントの誤検出などの問題が発生する可能性があります。正確なパターンの表示とスムーズなインジケーター動作を保証するために、これらの問題とその解決策についても詳しく説明します。

1.2.1. 強気パターン

強気ハーモニックパターンインジケーターを開発するために、パターンを構成する重要なスイングポイントを特定する体系的な手法を使用します。このプロセスでは、特定の価格ポイントを特定し、それらがハーモニックパターンのガイドラインに従っていることを確認します。

最初のステップとして、パターンの起点となるスイングロー(X)を識別します。次に、スイングハイ(A)とスイングロー(B)を識別します。B点はXAレッグの61.8%〜78.6%の間をリトレースしている必要があります。続いて、スイングハイ(C)を探し、スイングロー(D)を確認します。最終ポイントであるDがXよりも下に位置することで、強気パターンの全体構造が完成します。

これらの条件が満たされた場合、スイングポイントを結ぶトレンドライン、XABCDポイントのラベル、フィボナッチリトレースメントレベルなどのチャートオブジェクトを使用して、パターンをチャート上に視覚的に表現します。これにより、潜在的な強気の反転ゾーンを識別するための、体系的で透明性のあるアプローチが提供されます。さらに、パターン内の重要な取引ゾーンをより簡単に認識できるように、エントリーポジション、ストップロス(SL)、テイクプロフィット(TP)レベルを示すチャートオブジェクトも使用します。これにより、取引判断をサポートし、潜在的な強気反転ゾーンを特定するための体系的で透明な手法が提供されます。

図1:強気パターン

擬似コード

// ステップ1:スイングポイントを特定する

  • スイングロー(X)を検出
  • Xの後にスイングハイ(A)を特定
  • Aの後にスイングロー(B)を検出

BのリトレースメントがXAの61.8%〜78.6%の範囲にない場合

  • パターンを無効とし、再検出を開始  

BのリトレースメントがXAの61.8%〜78.6%の範囲内である場合

  • Bの後にスイングハイ(C)を特定
  • Cの後にスイングロー(D)を検出

DがXよりも下にない場合 

  • パターンを無効とし、再検出を開始

// ステップ2:チャートオブジェクトを描画する

  • X → A → B → C → Dを結ぶオブジェクトを描画 
  •  各ポイントにテキストオブジェクトでラベル付け(X、A、B、C、D)
  • 確認のためにXからAにかけてフィボナッチリトレースメントを描画 

// ステップ3:取引レベルを定義する 

  • エントリー、SL、TPを示すチャートオブジェクトを作成

1.2.2. 弱気パターン

強気パターンと構造は似ていますが、逆方向となるのが弱気ハーモニックパターンインジケーターです。ハーモニックパターンのガイドラインに従っていることを確認するために、重要なスイングポイントを正確に特定していきます。まず、スイングハイ(X)を識別し、次にスイングロー(A)を識別することでパターンの検出を開始します。その後、XAレッグの61.8%〜78.6%の範囲をリトレースする必要があるスイングハイ(B)を特定します。続いてスイングロー(C)を検出し、最終的なスイングハイ(D)を確認します。DがXよりも上にある場合、パターンが成立し、潜在的な弱気(下落)反転ゾーンが形成されます。

パターンの構造が確認された後は、トレンドライン、XABCDラベル、フィボナッチリトレースメントレベルなどのチャートオブジェクトを使用して、パターンを視覚的に表現します。さらに、パターン内の重要なトレードゾーンを明確にするため、エントリー位置、ストップロス(SL)、テイクプロフィット(TP)レベルをチャート上に表示します。

図2:弱気パターン

擬似コード

// ステップ1:スイングポイントを特定する

  • スイングハイ(X)を検出
  • Xの後にスイングロー(A)を検出
  • Aの後のスイングハイ(B)を検出

BのリトレースメントがXAの61.8%〜78.6%の範囲にない場合

  • パターンを無効とし、再検出を開始  

BのリトレースメントがXAの61.8%〜78.6%の範囲内である場合

  • Bの後にスイングロー(C)を検出
  • Cの後にスイングハイ(D)を検出

DがXより上にない場合

  • パターンを無効とし、再検出を開始

// ステップ2:チャートオブジェクトを描画する

  • X → A → B → C → Dを結ぶオブジェクトを描画 
  • 各ポイントにテキストオブジェクトでラベル付け(X、A、B、C、D) 
  • 確認のためにXからAにかけてフィボナッチリトレースメントを描画 

// ステップ3:取引レベルを定義する 

  • エントリー、SL、TPを示すチャートオブジェクトを作成


2.強気のハーモニックパターンの構築

このセクションでは、ハーモニックパターンインジケーターをMQL5に統合していきます。スイングポイントの特定、リトレースメントレベルの確認、およびチャートオブジェクトを使用したパターンの視覚化に必要な関数を定義します。さらに、描画されるオブジェクトの外観をカスタマイズし、視認性と使いやすさを向上させます。

2.1. スイングハイとスイングローの識別

ハーモニックパターンを正しく検出するには、チャート上でスイングハイとスイングローを識別する信頼性の高い手法が必要です。XABCD構造は、これらのスイングポイントをベースにプロットされます。スイングハイを識別するには、あるローソク足の高値が、指定された範囲内の他のローソク足の高値よりも高いかどうかを確認します。同様に、スイングローは、そのローソク足の安値が指定範囲内で最も低い場合に識別されます。この指定された範囲のサイズは、検出の感度を決定します。大きな値は、より大きなトレンドや主要なスイングを検出し、小さな値は、小さな価格変動を検出します。次のステップでは、過去の価格データをスキャンし、重要なスイングポイントを見つけ、パターン形成のルールに合致しているかを確認するアルゴリズムを開発します。

2.1.1. スイングハイおよびスイングロー関数

#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);
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING LOW                                           |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false; 
     }
   return true; 
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING HIGH                                          |
//+------------------------------------------------------------------+
bool IsSwingHigh(const double &high[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(high[index] < high[index - i] || high[index] < high[index + i])
         return false; 
     }
   return true; 
  }

説明

MetaTrader 5では、「#property indicator_chart_window」というディレクティブを使うことで、カスタムインジケーターをサブウィンドウではなく、メインチャート上に表示するよう指示できます。これは、ハーモニックパターンや価格に重ねるタイプのインジケーター(トレンドライン、サポート&レジスタンスなど)を作成する際に非常に有用です。このディレクティブを指定しない場合、インジケーターはRSIやMACDのような別ウィンドウにプロットされてしまう可能性があります。

IsSwingLow関数は、チャート上のスイングローを検出するためのものです。ローソク足の安値が、指定範囲内の前後のローソク足の安値よりも低い場合、その足はスイングローと見なされます。この関数は、前後に何本のローソク足を比較対象とするかを定めるルックバック値、安値の配列、そして評価対象のローソク足のインデックスを受け取ります。関数は、周囲のローソク足を反復処理することで、現在の安値が最も低いかどうかを判定します。周囲の範囲内により低い値が見つかった場合、そのローソク足はスイングローではないと判断され、falseが返されます。そうでなければtrueが返され、正当なスイングローであると認識されます。

これと同様に、スイングハイ(つまり、あるローソク足の高値が周囲のローソク足の高値を上回っているポイント)は、IsSwingHigh関数によって検出されます。この関数はIsSwingLowと同じロジックを使用しますが、最も低い値を探すのではなく、指定されたインデックスの高値がルックバック範囲内で最も高い値であることを確認します。周囲のローソク足のいずれかがより高い値を持っている場合は、falseを返します。そうでない場合は、スイングハイと判定し、trueを返します。

ハーモニックパターンを定義するための基盤となるのは、こうした重要な価格の転換点の検出機能です。スイングハイとスイングローを特定した後、それらをトレンドラインで結び、フィボナッチリトレースメントを使用して確認することで、パターンのXABCD構造をプロットすることができます。この方法によって、インジケーターは新しい価格情報に動的に対応し、検出されたパターンを適切に更新することが保証されます。

比喩的な説明

IsSwingLow関数の動作は、谷の中で最も低い地点を見つけることに例えることができます。ハイキングコースに立って、道の中で最も深いくぼみを探している自分を想像してみてください。ルックバック期間中に、少し前に進み、また少し後ろに戻ります。その範囲内で現在の地点が他のすべての地点よりも低ければ、そこが最も深いくぼみ(スイングロー)であると確認されます。逆に、周囲に自分より低い地点があれば、現在の場所はただの斜面の一部にすぎず、最も低いポイントではありません。この関数は、価格が反転して上昇し始める可能性のあるゾーンを特定するのに役立ちます。

IsSwingHigh関数を使うことは、山脈の中で最も高い地点を探すのに似ています。一か所に立ち、前後に数歩ずつ移動して、その範囲内で自分のいる地点が最も高ければ、それはスイングハイと見なされます。どのくらいの範囲をチェックするか(ルックバック期間)は、頂点や谷底をどこで確定させるかに大きく影響します。範囲が狭すぎると、小さな変動を重要なポイントと誤認する可能性がありますし、広すぎると、小さくても重要なトレンドを見逃してしまうかもしれません。このバランスによって、検出されるスイングポイントは単なる価格の揺らぎではなく、意味のある転換点として認識されます。

図3:スイングハイとスイングロー

2.1.2. スイングロー(X)の識別

次のステップは、作成済みのIsSwingLowおよびIsSwingHigh関数をOnCalculate関数に組み込むことです。ここでは、リアルタイムの価格データに対してスイングポイントの検出ロジックを適用します。最初の課題は、ハーモニックパターンの始点となる最初のスイングロー(X)を見つけることです。これを実現するために、先ほど作成した関数を使ってOnCalculate内の過去のローソク足データを繰り返し調べ、それぞれの足がスイングローの条件を満たしているかを判定していきます。

#property indicator_chart_window

// Input parameters
input int LookbackBars = 10; // Number of bars to look back/forward for swing points
input int bars_check  = 1000; // Number of bars to check for swing points

// CHART ID
long chart_id = ChartID(); // Get the ID of the current chart to manage objects (lines, text, etc.)

//X
double X; // Price of the swing low (X).
datetime X_time; // Time of the swing low (X).
string X_line; // Unique name for the trend line object.
string X_letter; // Unique name for the text label object.

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

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".

            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X
           }
        }
     }

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

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING LOW                                           |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {
 
   for(int i = 1; i <= lookback; i++)
     {
      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false;  
     }
   return true;  
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING HIGH                                          |
//+------------------------------------------------------------------+
bool IsSwingHigh(const double &high[], int index, int lookback)
  {

   for(int i = 1; i <= lookback; i++)
     {
      if(high[index] < high[index - i] || high[index] < high[index + i])
         return false; 
     }
   return true; 
  }
//+------------------------------------------------------------------+

出力

図4:スイングロー(X)

説明

まず、強気ハーモニックパターンを見つけるための最初のステップであるスイングロー(X)を特定するために、いくつかの重要な入力データを宣言します。特定のポイントが正当なスイングポイントであるかどうかを確認するために、その前後に調べるべきバーの本数はLookbackBars変数で決定されます。これにより、重要なスイングローとはならない小さな価格変動を除外するのに役立ちます。また、スクリプトの処理効率を保つために、処理する過去バーの数を制限するbars_check引数が設定されています。これにより、処理するバー数が適切に管理されます。

さらに、チャート上にトレンドラインやテキストラベルといったチャートオブジェクトを作成・管理するために、ChartID関数を使ってチャートIDを取得します。検出したスイングロー(X)の価格を保持する変数X、発生時間を記録するX_time、チャート上でこのポイントを識別するためのオブジェクトに固有の名前を付けるX_lineとX_letterを宣言します。スイングローを示すテキストラベルはX_letterを用いて作成し、視認性を高めるためにトレンドラインはX_lineを使って描画します。

これらの事前設定を踏まえて、OnCalculate関数内でスイングロー(X)を判定します。価格データが十分に揃っている場合にのみ処理を始めるように、「if(rates_total >= bars_check)」の条件を設けています。不完全な価格データをチェックしないように、ループは「rates_total - bars_check」から「rates_total - LookbackBars」までの過去バーを対象に繰り返し処理します。ループ内でIsSwingLow関数を使い、該当ポイントがスイングローかどうかを判定します。正当なスイングローが見つかれば、その時間と価格を記録し、オブジェクト名を一意に設定したうえで、チャート上に視覚的要素を作成します。

具体的には、「ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X)」により「X」という文字でスイングローを示すテキストオブジェクトを作成します。また、「ObjectCreate(chart_id, X_line, OBJ_TREND, 0, X_time, X, time[i+LookbackBars], X)」によって、Xレベルに沿ったトレンドラインを引き、検出されたスイングローをさらに明示します。これにより、ハーモニックパターン構造の最初の重要なポイントが正確に特定され、チャート上に表示されます。これが、パターンの次のポイントを決定するための土台となります。

2.1.3. スイングハイ(A)の識別

スイングロー(X)を正しく識別した後の次のステップは、スイングハイ(A)を見つけることです。このポイントは、Xの後に現れる最初の重要な上昇の動きであり、ハーモニックパターンの形成において欠かせません。Xを見つけたときと同様に、今回は谷(スイングロー)ではなく山(スイングハイ)を探すために、IsSwingHigh関数を用いてAを検出します。

具体的には、Xの後の価格データの中で、指定されたLookbackBars範囲内の周囲のバーの高値よりも高い高値を持つポイントを探します。正当なスイングハイが見つかったら、その価格と時間を記録し、一意の名前を付けたうえで、チャートオブジェクトを使って適切に表示します。

#property indicator_chart_window

// Input parameters
input int LookbackBars = 10; // Number of bars to look back/forward for swing points
input int bars_check  = 1000; // Number of bars to check for swing points

// CHART ID
long chart_id = ChartID(); // Get the ID of the current chart to manage objects (lines, text, etc.)

//X
double X; // Price of the swing low (X).
datetime X_time; // Time of the swing low (X).
string X_line; // Unique name for the trend line object.
string X_letter; // Unique name for the text label object.

//A
double A; // Price of the swing high (A).
datetime A_time; // Time of the swing high (A).
string A_line; // Unique name for the trend line object.
string A_letter; // Unique name for the text label object.

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

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X

            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars)  && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, A_time, A); // Create text object for A
                  ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                  ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                  ObjectCreate(chart_id,A_line,OBJ_TREND,0,A_time,A,time[j+LookbackBars],A); // Create line to mark A
                  ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                  break;
                 }
              }
           }
        }
     }

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

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING LOW                                           |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false;  
     }
   return true;  
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING HIGH                                          |
//+------------------------------------------------------------------+
bool IsSwingHigh(const double &high[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(high[index] < high[index - i] || high[index] < high[index + i])
         return false; 
     }
   return true; 
  }
//+------------------------------------------------------------------+

出力

図5:スイングハイ(A)

説明

まず、スイングハイ(A)を特定するために必要な変数を定義します。A_timeはスイングハイが発生した正確な時刻を記録し、Aはスイングハイの価格値を保持します。トレンドラインオブジェクトの名前にはA_lineを使用し、テキストラベルにはA_letterを用いることで、検出されたすべてのAポイントが固有の視覚的表現を持つようにします。これらの変数は、ハーモニックパターンの構造を視覚的に把握しやすくするため、チャートオブジェクトの作成に役立ちます。

Xを識別した後、コードはXの位置から価格データを順に調べてAを探します。IsSwingHigh関数は、指定されたLookbackBars範囲内でそのバーが局所的な高値かどうかを判定するために使用されます。条件として「time[j] > X_time」が用いられ、スイングハイAがXの後に来ることを保証します。 

この条件により、AのタイムスタンプがX_timeより大きい場合にのみAが選ばれ、ハーモニックパターンの正しい順序が維持されます。正当なスイングハイが見つかった場合、その価格と時間を記録し、トレンドラインとテキストラベルのオブジェクトに固有の名前を付与します。識別されたスイングハイを強調するために緑色のトレンドラインが描画され、文字「A」のテキストラベルがその位置に設置されます。最初の正当なスイングハイ(A)が見つかったら、break;文でループを抜けます。break;がなければループはさらにスイングハイを探し続け、後のスイングハイでAが上書きされる可能性があります。Xの直後に現れる最初のAだけを取得したいため、break;文はスイングハイを検出次第ループを終了させ、最初の有効なAを保持し、不必要な計算を避ける役割を果たします。 

2.1.4. スイングロー(B)の識別

スイングハイ(A)を特定した後の次のステップは、次のスイングロー(B)を見つけることです。BはAの後に来なければならないため、Bの探索はAを検出した直後から開始されます。価格データの中でAの位置からループを回し、IsSwingLow関数を使って、LookbackBars範囲内の近隣のバーと比較しながら、そのバーがスイングローであるかを判定します。なお、ハーモニックパターンの判定ではBはXAの特定のフィボナッチリトレースメントレベルを下回ることが期待されますが、今回はフィボナッチの検証については扱わず、Bの検出のみに注目します。

スイングローが検出されると、その価格と時間がそれぞれBとB_timeに記録されます。また、チャート上でこのポイントを示すために、トレンドライン用のB_lineとテキストラベル用のB_letterという固有の名前を割り当てます。スイングローの地点には「B」と表示されたテキストオブジェクトが作成され、それを強調するトレンドラインも描画されます。この段階で、ハーモニックパターンの骨格となる3つの主要ポイント、X、A、Bが正しく揃うことになります。

#property indicator_chart_window

// Input parameters
input int LookbackBars = 10; // Number of bars to look back/forward for swing points
input int bars_check  = 1000; // Number of bars to check for swing points

// CHART ID
long chart_id = ChartID(); // Get the ID of the current chart to manage objects (lines, text, etc.)

//X
double X; // Price of the swing low (X).
datetime X_time; // Time of the swing low (X).
string X_line; // Unique name for the trend line object.
string X_letter; // Unique name for the text label object.

//A
double A; // Price of the swing high (A).
datetime A_time; // Time of the swing high (A).
string A_line; // Unique name for the trend line object.
string A_letter; // Unique name for the text label object.

//B
double B; // Price of the swing low (B).
datetime B_time; // Time of the swing low (B).
string B_line; // Unique name for the trend line object.
string B_letter; // Unique name for the text label object.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// This function is called when the indicator is removed or the chart is closed.
// Delete all objects (lines, text, etc.) from the chart to clean up.
   ObjectsDeleteAll(chart_id);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X


            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars) && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, A_time, A); // Create text object for A
                  ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                  ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                  ObjectCreate(chart_id,A_line,OBJ_TREND,0,A_time,A,time[j+LookbackBars],A); // Create line to mark A
                  ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green


                  for(int k = j; k < rates_total - LookbackBars; k++)
                    {
                     if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
                       {

                        // If a swing low is found, store its price, time, and create a name for the object.
                        B = low[k]; // Price of the swing low (B).
                        B_time = time[k]; // Time of the swing low (B).
                        B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
                        B_letter = StringFormat("B%d", k); // Unique name for the text label object.

                        ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, B_time, B); // Create text object for B
                        ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                        ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                        ObjectCreate(chart_id,B_line,OBJ_TREND,0,B_time,B,time[k+LookbackBars],B); // Create line to mark B
                        ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to green


                        break;

                       }
                    }

                  break;
                 }
              }
           }
        }
     }

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

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING LOW                                           |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false;  
     }
   return true; 
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING HIGH                                          |
//+------------------------------------------------------------------+
bool IsSwingHigh(const double &high[], int index, int lookback)
  {

   for(int i = 1; i <= lookback; i++)
     {
      if(high[index] < high[index - i] || high[index] < high[index + i])
         return false;  
     }
   return true;  
  }
//+------------------------------------------------------------------+

出力

図6:スイングロー(B)

説明

Aに続くスイングローの価格は変数Bで表されます。Bを特定するために、Aの位置から始まるループでIsSwingLow関数を用いて次のスイングローを探します。見つかった後は、その価格と時間、さらにトレンドラインおよびテキストラベルに使う固有の名前を保存します。続いて、チャート上にBを示すために、ミッドナイトブルーのトレンドラインと緑色の「B」ラベルのテキストオブジェクトを作成します。パターン生成におけるスイングポイントの正しい順序を維持するため、最初に見つかった有効なBだけを選ぶようにbreak文でループを抜けます。ただし、現在の実装ではループ処理の中でXとBの両方がスイングローとして認識されるため、XとBが重複することがあります。プログラムは各スイングポイントを順に評価するため、この挙動は想定されるものですが、もしXとBが同じ場合、チャート上に重複した注釈が表示される可能性があります。

もしXとBが重複しないようにしたい場合は、「BはAの後に来る別のスイングローであり、Xとは異なる」という条件を追加できます。この設定はコードにオプションとして組み込み可能です。オプションを許可すれば、現在のようにXとBが同じスイングローとなることがありますが、禁止すればBはXとは異なるスイングローとして認識されます。

BがXとは別のローであることを必須とすると、発見されるハーモニックパターンの数は減少します。しかし、これはユーザーのパターン認識の好みに応じて柔軟に選択できるオプションとなっています。

input bool overlap = false; //Allow Overlaping
for(int k = j; k < rates_total - LookbackBars; k++)
  {
   if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
     {

      // If a swing low is found, store its price, time, and create a name for the object.
      B = low[k]; // Price of the swing low (B).
      B_time = time[k]; // Time of the swing low (B).
      B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
      B_letter = StringFormat("B%d", k); // Unique name for the text label object.

      ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, B_time, B); // Create text object for B
      ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
      ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,B_line,OBJ_TREND,0,B_time,B,time[k+LookbackBars],B); // Create line to mark B
      ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to green

      if(overlap == false)
        {
         i = k;
        }
      if(overlap == true)
        {
         i = i;
        }

      break;

     }
  }
出力


図7:XとBの重なり

説明

XとBが同じスイングローを共有できるかどうかは、overlap入力パラメータによって決まります。「i = k;」という行は、Bが見つかった時点でループの繰り返しを進めてスキップさせることを保証し、overlapがfalseの場合にBがXと同じになることを防ぎます。これにより、スイングポイント間に明確な区別を保ちつつ、認識されるハーモニックパターンの数は制限されるものの、重複を最小限に抑えられます。

一方、「i = i;」という行は、overlapがtrueの場合にループを通常通り継続させ、スキップを必要としません。これにより、XとBが同じ価格水準に自然に存在する場合でも重複を許し、より多くのハーモニックパターンを検出できるようになります。ただし、パターン表示に若干の重複が生じる可能性もあります。 XとBの重複を確実に防ぐことで、コードはそれらを別個のスイングポイントとして区別しています。図が示すように、BはXとは独立して存在し、より明確なパターン構造を維持しています。

2.1.5. スイングハイ(C)の識別

スイングロー(X)、スイングハイ(A)、続くスイングロー(B)を特定した後、次にスイングハイ(C)を見つけます。このポイントは、ハーモニックパターンの全体的な形状や潜在的な反転ゾーンを決定するため、パターン構造の構築において重要です。

トレンドライン用のC_lineとテキストラベル用のC_letterにはそれぞれ固有の名前が付けられ、このポイントを視覚的に示します。チャート上のスイングハイ位置には「C」というラベルのテキストオブジェクトが配置され、それを強調するトレンドラインも描かれます。この段階で、ハーモニックパターンの構造を形作る4つの主要ポイント、X、A、B、Cが揃ったことが保証されます。

//C
double C; // Price of the swing high (C).
datetime C_time; // Time of the swing high (C).
string C_line; // Unique name for the trend line object.
string C_letter; // Unique name for the text label object.
//+------------------------------------------------------------------+
//| 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[])
  {
//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X

            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars) && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, A_time, A); // Create text object for A
                  ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                  ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                  ObjectCreate(chart_id,A_line,OBJ_TREND,0,A_time,A,time[j+LookbackBars],A); // Create line to mark A
                  ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                  for(int k = j; k < rates_total - LookbackBars; k++)
                    {
                     if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
                       {

                        // If a swing low is found, store its price, time, and create a name for the object.
                        B = low[k]; // Price of the swing low (B).
                        B_time = time[k]; // Time of the swing low (B).
                        B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
                        B_letter = StringFormat("B%d", k); // Unique name for the text label object.

                        ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, B_time, B); // Create text object for B
                        ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                        ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                        ObjectCreate(chart_id,B_line,OBJ_TREND,0,B_time,B,time[k+LookbackBars],B); // Create line to mark B
                        ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

                        for(int l = j ; l < rates_total - LookbackBars; l++)
                          {
                           if(IsSwingHigh(high, l, LookbackBars) && time[l] > B_time)
                             {
                              C = high[l]; // Price of the swing high (C).
                              C_time = time[l]; // Time of the swing high (C).
                              C_line = StringFormat("CHigh%d", l); // Unique name for the trend line object.
                              C_letter = StringFormat("C%d", l); // Unique name for the text label object.

                              ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, C_time, C); // Create text object for C
                              ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
                              ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                              ObjectCreate(chart_id,C_line,OBJ_TREND,0,C_time,C,time[l+LookbackBars],C); // Create line to mark C
                              ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                              if(overlap == false)
                                {
                                 i = l;
                                }
                              if(overlap == true)
                                {
                                 i = i;
                                }

                              break;

                             }
                          }

                        break;

                       }
                    }

                  break;
                 }
              }
           }
        }
     }

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


図8:スイングハイ(C)

説明

スイングロー(B)を識別した後、このコード部分は次の重要なステップであるスイングハイ(C)の判定を担当します。価格データに対してループ「for(int l = j; l < rates_total - LookbackBars; l++)」が実行されます。ここでの開始インデックスjは、前回のスイングハイ(A)が見つかった位置です。CがBの後に来ることを保証するため、最新のバーまで調べ続けます。パターンの正しい順序を維持するため、「if(IsSwingHigh(high, l, LookbackBars) && time[l] > B_time)」という条件で、指定されたルックバック範囲内でそのバーがスイングハイであり、かつタイムスタンプがBの時間より後であることを確認します。 

正当なスイングハイが見つかると、その価格と時間がそれぞれCとC_timeに保存され、トレンドラインとテキストラベル用のオブジェクト名としてC_lineとC_letterが割り当てられます。「ObjectCreate(chart_id, C_line, OBJ_TREND, 0, C_time, C, time[l+LookbackBars], C)」によって、指定されたスイングハイ位置に「C」のテキストラベルを強調するトレンドラインが作成されます。さらに、「ObjectSetInteger(chart_id, C_line, OBJPROP_COLOR, clrSaddleBrown);」によって、Cのトレンドラインの色をSaddleBrownに設定し、他のラインと視覚的に区別します。

最後の条件ブロックは、重複パターンの扱いを適切に管理します。「i = l;」はoverlapがfalseの場合、前のスイングポイントが別のパターンに使われるのを防ぎます。一方、overlapがtrueの場合は「i = i;」により現在の値を保持し、複数のパターンが重複することを許容します。最初の正当なスイングハイ(C)が判明したら、break;によりループを終了し、不要な繰り返し処理を避けて効率化を図ります。

2.1.6. スイングロー(D)の識別

スイングハイ(C)を識別した後にスイングロー(D)を識別することで、ハーモニックパターンの生成に必要なプライスアクションの順序が正しく保たれるようになります。Dを探す処理は、Cが検出された位置から時間順に次のスイングローを見つけることを目的として開始されます。有効なスイングローと認めるためには、2つの条件を満たす必要があります。第一に、指定されたルックバック期間内でその価格がスイングローと判定されること。第二に、パターンの正しい順序を維持するために、そのタイムスタンプがCよりも後であることです。

正当なスイングローが見つかった場合は、その価格と時間を記録し、対応するトレンドラインおよびテキストラベルに固有の識別子を割り当てます。パターン内でスイングローを視覚的に把握しやすくするために、Dの位置にトレンドラインを描き、それを示すテキストラベルを配置して強調表示します。

//D
double D; // Price of the swing low (D).
datetime D_time; // Time of the swing low (D).
string D_line; // Unique name for the trend line object.
string D_letter; // Unique name for the text label object.

//Trend
string XA_line; // Unique name for XA trend line object.
string AB_line; // Unique name for AB trend line object.
string BC_line; // Unique name for BC trend line object.
string CD_line; // Unique name for CD trend line object.

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

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X

            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars) && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, A_time, A); // Create text object for A
                  ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                  ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                  ObjectCreate(chart_id,A_line,OBJ_TREND,0,A_time,A,time[j+LookbackBars],A); // Create line to mark A
                  ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                  for(int k = j; k < rates_total - LookbackBars; k++)
                    {
                     if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
                       {

                        // If a swing low is found, store its price, time, and create a name for the object.
                        B = low[k]; // Price of the swing low (B).
                        B_time = time[k]; // Time of the swing low (B).
                        B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
                        B_letter = StringFormat("B%d", k); // Unique name for the text label object.

                        ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, B_time, B); // Create text object for B
                        ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                        ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                        ObjectCreate(chart_id,B_line,OBJ_TREND,0,B_time,B,time[k+LookbackBars],B); // Create line to mark B
                        ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

                        for(int l = j ; l < rates_total - LookbackBars; l++)
                          {
                           if(IsSwingHigh(high, l, LookbackBars) && time[l] > B_time)
                             {
                              C = high[l]; // Price of the swing high (C).
                              C_time = time[l]; // Time of the swing high (C).
                              C_line = StringFormat("CHigh%d", l); // Unique name for the trend line object.
                              C_letter = StringFormat("C%d", l); // Unique name for the text label object.

                              ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, C_time, C); // Create text object for C
                              ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
                              ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                              ObjectCreate(chart_id,C_line,OBJ_TREND,0,C_time,C,time[l+LookbackBars],C); // Create line to mark C
                              ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                              for(int m = l; m < rates_total - (LookbackBars / 2); m++)
                                {
                                 if(IsSwingLow(low, m, LookbackBars / 2) && time[m] > C_time)
                                   {
                                    D = low[m]; // Price of the swing low (D).
                                    D_time = time[m]; // Time of the swing low (D).
                                    D_line = StringFormat("DLow%d", m); // Unique name for the trend line object.
                                    D_letter = StringFormat("D%d", m); // Unique name for the text label object.

                                    ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
                                    ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
                                    ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
                                    ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
                                    ObjectCreate(chart_id,XA_line,OBJ_TREND,0,X_time,X,A_time,A); // Create line to connect XA
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

                                    AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
                                    ObjectCreate(chart_id,AB_line,OBJ_TREND,0,A_time,A,B_time,B); // Create line to connect AB
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

                                    BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
                                    ObjectCreate(chart_id,BC_line,OBJ_TREND,0,B_time,B,C_time,C); // Create line to connect BC
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

                                    CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
                                    ObjectCreate(chart_id,CD_line,OBJ_TREND,0,C_time,C,D_time,D); // Create line to connect CD
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

                                    if(overlap == false)
                                      {
                                       i = m;
                                      }
                                    if(overlap == true)
                                      {
                                       i = i;
                                      }
                                    break;

                                   }
                                }

                              break;

                             }
                          }

                        break;

                       }
                    }

                  break;
                 }
              }
           }
        }
     }

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

出力

図9:スイングロー(D)

説明

認識されたパターンにおけるスイングローDの価格は、変数Dで表されます。Dはハーモニックパターン取引において非常に重要なポイントであり、プライスアクションが反転し、パターンが完結する可能性のある場所です。D_timeはこのローが発生した時刻を記録します。また、チャート上でこのスイングローを視覚的に識別するために、トレンドラインとテキストラベルがD_lineおよびD_letterとして作成・ラベル付けされます。

プログラムは、「for(int m = l; m < rates_total - (LookbackBars / 2); m++)」というループで価格データを走査し、ポイントDを探します。ループ内ではIsSwingLow関数を使用して、インデックスmの価格がスイングローかどうかを判断し、そのローがCの時刻より後であることを確認します。有効なスイングローが見つかった場合、その価格と時刻はそれぞれDおよびD_timeに代入されます。

ポイントDが検出されると、インジケーターはチャート上に視覚的な要素を描画します。ObjectCreate関数により、スイングローの位置に文字「D」を表示するテキストラベル(D_letter)が作成され、視認性を高めるために緑色に設定されます。また、視覚的な一貫性を保つため、Dの位置にブラウン色(clrSaddleBrown)のトレンドライン(D_line)が描かれ、LookbackBarsの期間分延長されます。

この時点で、プログラムはすでに特定されたスイングポイントを接続するトレンドラインも作成します。XからA、AからB、BからC、そしてCからDをそれぞれ結ぶXA_line、AB_line、BC_line、CD_lineというオブジェクトが作成され、パターンの構造を視覚的に明示します。これらのラインは、トレーダーが価格の動きの可能性を分析するのに役立ちます。各ラインの太さや色も視認性を高めるために調整されます。

XABCDパターンを正常に認識した後には、いくつかの重要な問題に対処する必要があります。現在のプログラムのロジックでは、Xを一度特定した後は、ABCDのシーケンスが完了するまでXを更新しません。つまり、XとAの間に新たにXよりも低い安値が発生しても、プログラムはXを更新しないということになります。そのため、パターンが実際の市場構造を正しく反映しなくなる可能性があります。

この問題を解決し、パターンの妥当性を保証するためには、「XとAの間でXが依然として最も低い安値であるかどうか」を継続的に確認する仕組みを導入する必要があります。この範囲内により低いローが発生した場合は、Xを動的に更新すべきです。同様に、AはAとBの間で最も高い高値であるべきであり、CはCとDの間で最も高い高値、そしてBはBとCの間で最も低い安値であるべきです。これらの条件を満たすことで、パターン検出の精度を向上させ、厳密すぎるポイント選定による誤認識を防ぐことができます。このアプローチにより、ハーモニックパターンの構造の整合性を維持しつつ、インジケーターが新しい価格動向にも柔軟に対応できるようになります。

//X
int x_a_bars; // Number of bars between XA
int x_lowest_index; // Index of the lowest bar
double x_a_ll; // Price of the lowest bar
datetime x_a_ll_t; // Time of the lowest bar

//A
int a_b_bars; // Number of bars between AB
int a_highest_index; // Index of the highest bar
double a_b_hh; // Price of the highest bar
datetime a_b_hh_t; // Time of the highest bar

//B
int b_c_bars; // Number of bars between BC
int b_lowest_index; // Index of the lowest bar
double b_c_ll; // Price of the lowest bar
datetime b_c_ll_t; // Time of the lowest bar

//C
int c_d_bars; // Number of bars between CD
int c_highest_index; // Index of the highest bar
double c_d_hh; // Price of the highest bar
datetime c_d_hh_t; // Time of the highest bar

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

//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars) && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  for(int k = j; k < rates_total - LookbackBars; k++)
                    {
                     if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
                       {

                        // If a swing low is found, store its price, time, and create a name for the object.
                        B = low[k]; // Price of the swing low (B).
                        B_time = time[k]; // Time of the swing low (B).
                        B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
                        B_letter = StringFormat("B%d", k); // Unique name for the text label object.

                        for(int l = j ; l < rates_total - LookbackBars; l++)
                          {
                           if(IsSwingHigh(high, l, LookbackBars) && time[l] > B_time)
                             {
                              C = high[l]; // Price of the swing high (C).
                              C_time = time[l]; // Time of the swing high (C).
                              C_line = StringFormat("CHigh%d", l); // Unique name for the trend line object.
                              C_letter = StringFormat("C%d", l); // Unique name for the text label object.

                              for(int m = l; m < rates_total - (LookbackBars / 2); m++)
                                {
                                 if(IsSwingLow(low, m, LookbackBars / 2) && time[m] > C_time)
                                   {
                                    D = low[m]; // Price of the swing low (D).
                                    D_time = time[m]; // Time of the swing low (D).
                                    D_line = StringFormat("DLow%d", m); // Unique name for the trend line object.
                                    D_letter = StringFormat("D%d", m); // Unique name for the text label object.

                                    //D
                                    ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
                                    ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
                                    ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
                                    ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    //C
                                    c_d_bars = Bars(_Symbol,PERIOD_CURRENT,C_time, D_time);
                                    c_highest_index = ArrayMaximum(high,l, c_d_bars);

                                    c_d_hh = high[c_highest_index]; //C - D Highest High and time
                                    c_d_hh_t = time[c_highest_index];

                                    ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_hh_t, c_d_hh); // Create text object for C
                                    ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
                                    ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_hh_t,C,time[c_highest_index+LookbackBars],c_d_hh); // Create line to mark C
                                    ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    //B
                                    b_c_bars = Bars(_Symbol,PERIOD_CURRENT,B_time, c_d_hh_t);
                                    b_lowest_index = ArrayMinimum(low,k, b_c_bars);

                                    b_c_ll = low[b_lowest_index]; //B - C Lowest Low and time
                                    b_c_ll_t = time[b_lowest_index];

                                    ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_ll_t, b_c_ll); // Create text object for B
                                    ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                                    ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,time[b_lowest_index+LookbackBars],b_c_ll); // Create line to mark B
                                    ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

                                    //A
                                    a_b_bars = Bars(_Symbol,PERIOD_CURRENT,A_time, b_c_ll_t);
                                    a_highest_index = ArrayMaximum(high,j, a_b_bars);

                                    a_b_hh = high[a_highest_index]; //A - B Highest High and time
                                    a_b_hh_t = time[a_highest_index];

                                    ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_hh_t, a_b_hh); // Create text object for A
                                    ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                                    ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,time[a_highest_index+LookbackBars],a_b_hh); // Create line to mark A
                                    ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                                    //X
                                    x_a_bars = Bars(_Symbol,PERIOD_CURRENT,X_time, a_b_hh_t);
                                    x_lowest_index = ArrayMinimum(low,i, x_a_bars);

                                    x_a_ll = low[x_lowest_index]; //X - A Lowest Low and time
                                    x_a_ll_t = time[x_lowest_index];

                                    ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_ll_t, x_a_ll); // Create text object for X
                                    ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
                                    ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,time[x_lowest_index+LookbackBars],x_a_ll); // Create line to mark X

                                    XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
                                    ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create line to connect XA
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

                                    AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
                                    ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); // Create line to connect AB
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

                                    BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
                                    ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); // Create line to connect BC
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

                                    CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
                                    ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_hh_t,c_d_hh,D_time,D); // Create line to connect CD
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

                                    if(overlap == false)
                                      {
                                       i = m;
                                      }
                                    if(overlap == true)
                                      {
                                       i = i;
                                      }
                                    break;

                                   }
                                }

                              break;

                             }
                          }

                        break;

                       }
                    }

                  break;
                 }
              }
           }
        }
     }

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

出力

図10:新しいXABCD

説明

Xポイントは、ハーモニックパターントレードにおいて反転パターンを検出するための初期基準点として機能します。強気パターンではそれは大きなスイングローを意味し、弱気パターンではスイングハイを示します。Xはフィボナッチリトレースメントやエクステンションの測定の基礎となるため、ハーモニックパターンの形成を確認するうえで重要なポイントです。このコードの目的は、Xを認識し、その時刻と価格を記録し、チャート上に視覚的に示すことです。そして最終的に、Xを他のスイングポイント(A、B、C、D)と結びつけて、パターン全体の構造を構築します。

Xに関するデータを記録するために、いくつかの重要な変数が使用されます。XとAの間のバー数は変数x_a_barsで記録され、これはパターンの各レッグ間の相対的な距離を把握するのに役立ちます。Xが出現した正確なバーを特定するために、x_lowest_indexはこの範囲内で最も低い価格の配列インデックスを保持します。最低価格に対応する時刻はx_a_ll_tに保存され、価格自体はx_a_llに格納されます。

Xを決定する最初のステップは、Bars関数を使用してXとAの間のバー数を取得することです。この関数は、分析に必要な範囲を提供し、この2点間のバー数をカウントします。指定された範囲内で最低価格を持つインデックスを検索するために、プログラムはArrayMinimum関数を使用します。次に、low[x_lowest_index]とtime[x_lowest_index]の配列からXの実際の価格と時間が取得されます。

Xが識別されると、スクリプトはMetaTraderのオブジェクト機能を使って、チャート上にそれを視覚的に表示します。重要なポイントであるXを一目で認識できるように、ObjectCreate関数を使ってテキストラベルX_letterがXのスイングローの位置に作成されます。ラベルには「X」という文字が与えられ、Xの価格と時刻の位置に配置されます。スイングローを明確に強調するため、ObjectCreate関数によってXの位置にトレンドライン(X_line)も作成されます。このラインはLookbackBarsで指定されたバー数分延長されます。

Xが決定された後、プログラムはXと他の重要なポイント(A、B、C、D)を結ぶトレンドラインを作成します。これにより、ハーモニックパターンをより明確に視覚化できます。最初の接続線であるXAラインは、ObjectCreate関数を使ってXとAを結びます。このラインは視認性を高めるため、太さ3ピクセルでブラウン(clrSaddleBrown)に設定されています。その他のパターンレッグ、すなわちAからBを結ぶABライン、BからCを結ぶBCライン、CからDを結ぶCDラインも、同様にトレンドラインで描画されます。これらの各ラインは、統一された視覚表現を実現するため、同じ太さと色の設定が保たれます。

2.2. XAのフィボナッチリトレースメントを用いたポイントBの検証

このセクションでは、スイングローBがXAレッグの78.6%リトレースメントより上にあり、かつ61.8%リトレースメントより下にあるかどうかを確認することで、Bを検証します。この検証フェーズは、Bが必要なフィボナッチ比率に適合していることを保証し、パターン構造の定義に役立つため、ブル型パターントレードにおいて重要です。Bがこの範囲内にある場合、正当なハーモニックパターンの形成の可能性が高くなります。逆に、Bが高すぎたり低すぎたりする場合は、パターンが正規のものではない、あるいはさらなる確認が必要である可能性があります。

この検証を実行するために、まずXAレッグに対してフィボナッチリトレースメントレベルを算出します。フィボナッチリトレースメントは、価格の反転ポイントを見極めるための一般的なテクニカル分析手法です。

Bの妥当性を確認するだけでなく、チャート上の可視化にフィボナッチリトレースメントオブジェクトを追加するために、MQL5のグラフィカルツールを使用します。ObjectCreate関数を用いてフィボナッチツールをプロットし、Xを開始点、Aを終点として設定します。オブジェクトの作成後、MetaTrader 5がデフォルトでサポートしていない追加のフィボナッチレベルも含めるようにオブジェクトを編集します。これにより、すべての重要なリトレースメントゾーンが表示されることが保証されます。

//Fibo
string XA_fibo; // Unique name for XA fibo
double lvl_61_8; // Level 61.8
double lvl_78_6; // Level 78.6
string fibo_618_786; // Unique name for the object that marks 61.8 and 78.6.
string fibo_78_6_txt; // Unique name for text "78.6" cause its not available by default
for(int m = l; m < rates_total - (LookbackBars / 2); m++)
  {
   if(IsSwingLow(low, m, LookbackBars / 2) && time[m] > C_time)
     {
      D = low[m]; // Price of the swing low (D).
      D_time = time[m]; // Time of the swing low (D).
      D_line = StringFormat("DLow%d", m); // Unique name for the trend line object.
      D_letter = StringFormat("D%d", m); // Unique name for the text label object.

      //D
      ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
      ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
      ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
      ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

      //C
      c_d_bars = Bars(_Symbol,PERIOD_CURRENT,C_time, D_time);
      c_highest_index = ArrayMaximum(high,l, c_d_bars);

      c_d_hh = high[c_highest_index]; //C - D Highest High and time
      c_d_hh_t = time[c_highest_index];

      ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_hh_t, c_d_hh); // Create text object for C
      ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
      ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_hh_t,C,time[c_highest_index+LookbackBars],c_d_hh); // Create line to mark C
      ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

      //B
      b_c_bars = Bars(_Symbol,PERIOD_CURRENT,B_time, c_d_hh_t);
      b_lowest_index = ArrayMinimum(low,k, b_c_bars);

      b_c_ll = low[b_lowest_index]; //B - C Lowest Low and time
      b_c_ll_t = time[b_lowest_index];

      ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_ll_t, b_c_ll); // Create text object for B
      ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
      ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,time[b_lowest_index+LookbackBars],b_c_ll); // Create line to mark B
      ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

      //A
      a_b_bars = Bars(_Symbol,PERIOD_CURRENT,A_time, b_c_ll_t);
      a_highest_index = ArrayMaximum(high,j, a_b_bars);

      a_b_hh = high[a_highest_index]; //A - B Highest High and time
      a_b_hh_t = time[a_highest_index];

      ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_hh_t, a_b_hh); // Create text object for A
      ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
      ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,time[a_highest_index+LookbackBars],a_b_hh); // Create line to mark A
      ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

      //X
      x_a_bars = Bars(_Symbol,PERIOD_CURRENT,X_time, a_b_hh_t);
      x_lowest_index = ArrayMinimum(low,i, x_a_bars);

      x_a_ll = low[x_lowest_index]; //X - A Lowest Low and time
      x_a_ll_t = time[x_lowest_index];

      ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_ll_t, x_a_ll); // Create text object for X
      ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
      ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,time[x_lowest_index+LookbackBars],x_a_ll); // Create line to mark X

      XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
      ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create line to connect XA
      ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
      ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

      AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
      ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); // Create line to connect AB
      ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
      ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

      BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
      ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); // Create line to connect BC
      ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
      ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

      CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
      ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_hh_t,c_d_hh,D_time,D); // Create line to connect CD
      ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
      ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

      lvl_61_8 = a_b_hh - ((61.8/100) * (a_b_hh - x_a_ll)); // Calculating level 61.8
      lvl_78_6 = a_b_hh - ((78.6/100) * (a_b_hh - x_a_ll)); // Calculating level 78.6

      //XA FIBO
      XA_fibo = StringFormat("XA FIB0 %d", i);
      ObjectCreate(chart_id,XA_fibo,OBJ_FIBO,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create XA fibo
      ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELS,6); // Number of default levels
      for(int i = 1; i <= 6; i++)
        {

         ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELCOLOR,i,clrSaddleBrown); // Set each level color to SaddleBrown

        }

      fibo_618_786 = StringFormat("Fibo 78.6 - 61.8 %d", i);
      fibo_78_6_txt = StringFormat("Fibo 78.6 Text %d", i);

      ObjectCreate(chart_id,fibo_618_786,OBJ_RECTANGLE,0,x_a_ll_t, lvl_61_8,b_c_ll_t,lvl_78_6); // Create rectangle object marking 61.8 and 78.6
      ObjectSetInteger(chart_id,fibo_618_786,OBJPROP_COLOR,clrSaddleBrown); // Set color to clrSaddleBrown

      ObjectCreate(chart_id,fibo_78_6_txt,OBJ_TEXT,0,b_c_ll_t,lvl_78_6); // Create text for level 78.6
      ObjectSetString(chart_id,fibo_78_6_txt,OBJPROP_TEXT,"78.6"); // Text to be displayed
      ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_COLOR,clrSaddleBrown); // Set text color
      ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_FONTSIZE,8); // Set text size

      if(overlap == false)
        {
         i = m;
        }
      if(overlap == true)
        {
         i = i;
        }
      break;

     }
  }
出力

図11:フィボ

説明

このセクションでは、ポイントBが所定の範囲内にあるかどうかを確認するために、XAレッグに対してフィボナッチリトレースメントを適用します。テクニカル分析において、フィボナッチリトレースメントは反転ゾーンを特定するためによく使われる手法です。特にBが、XAのリトレースメントとして想定されるレベルに一致しているかを検証するために不可欠です。具体的には、BはXAの61.8%〜78.6%のリトレースメント範囲内にあることが理想とされます。この範囲をチャート上で視覚的にハイライトすることで、Bが許容範囲内にあるかどうかをより簡単に判定できるようになります。この目的を達成するため、まずはいくつかの重要な変数を定義します。フィボナッチ描画が正確に識別されるよう、XA_fiboという変数にフィボナッチリトレースメントオブジェクトの一意な名前を保持します。

リトレースメントレベルが決定された後、ObjectCreate関数を使用してXAレッグ上にフィボナッチリトレースメントオブジェクトを作成します。このオブジェクトは、X(安値)からA(高値)までを結ぶことで、価格がフィボナッチレベルとどのように相互作用するかを視覚的に確認できます。フィボナッチレベルの数は6つに設定され、視認性を高めるためにその色はSaddleBrownに変更されます。これにより、各レベルが他のチャート要素と明確に区別できるようになります。 

さらに、重要なゾーンである61.8%〜78.6%のリトレースメント範囲を強調するために、長方形のオブジェクトを作成してそのエリアを可視化します。この長方形は61.8%から78.6%のレベル間をカバーするため、ポイントBが想定された範囲内にあるかどうかを即座に確認できます。これにより、個別に各リトレースメントレベルを調べる必要がなくなり、パターンの迅速な検証が可能になります。この長方形にもSaddleBrownの色が使用され、チャート全体の視覚的統一感が保たれます。

78.6%リトレースメントレベルに対してテキストラベルを追加することも、もうひとつの重要な変更点です。MetaTrader 5のフィボナッチツールは、デフォルトではこのレベルを含んでいないため、該当する価格レベルに「78.6」と表示するテキストオブジェクトを手動で生成します。これにより、トレーダーが78.6%リトレースメントの正確な位置を視認できるようになり、ハーモニックパターンの特定精度が向上します。こうした変更を実装することで、ポイントBがハーモニックパターン内で有効かどうかをより簡単に検証できるようになります。フィボナッチリトレースメントオブジェクト、マークされた61.8%〜78.6%ゾーン、そして追加されたテキストラベルによって、ハーモニックパターンの検証において正確かつ視覚的に直感的な手法が実現されます。 

すべての準備が整った今、パターンが有効であるための条件が満たされている場合にのみ、チャートオブジェクトが描画されるようにする必要があります。具体的には、ポイントDがポイントXよりも下に位置し、かつポイントBがXAの61.8%〜78.6%のリトレースメント範囲内にあることが求められます。これらの条件が満たされない場合、チャート上にいかなるオブジェクトも追加されるべきではありません。

for(int m = l; m < rates_total - (LookbackBars / 2); m++)
  {
   if(IsSwingLow(low, m, LookbackBars / 2) && time[m] > C_time)
     {
      D = low[m]; // Price of the swing low (D).
      D_time = time[m]; // Time of the swing low (D).
      D_line = StringFormat("DLow%d", m); // Unique name for the trend line object.
      D_letter = StringFormat("D%d", m); // Unique name for the text label object.

      //C
      c_d_bars = Bars(_Symbol,PERIOD_CURRENT,C_time, D_time);
      c_highest_index = ArrayMaximum(high,l, c_d_bars);

      c_d_hh = high[c_highest_index]; //C - D Highest High and time
      c_d_hh_t = time[c_highest_index];

      //B
      b_c_bars = Bars(_Symbol,PERIOD_CURRENT,B_time, c_d_hh_t);
      b_lowest_index = ArrayMinimum(low,k, b_c_bars);

      b_c_ll = low[b_lowest_index]; //B - C Lowest Low and time
      b_c_ll_t = time[b_lowest_index];

      //A
      a_b_bars = Bars(_Symbol,PERIOD_CURRENT,A_time, b_c_ll_t);
      a_highest_index = ArrayMaximum(high,j, a_b_bars);

      a_b_hh = high[a_highest_index]; //A - B Highest High and time
      a_b_hh_t = time[a_highest_index];

      //X
      x_a_bars = Bars(_Symbol,PERIOD_CURRENT,X_time, a_b_hh_t);
      x_lowest_index = ArrayMinimum(low,i, x_a_bars);

      x_a_ll = low[x_lowest_index]; //X - A Lowest Low and time
      x_a_ll_t = time[x_lowest_index];

      lvl_61_8 = a_b_hh - ((61.8/100) * (a_b_hh - x_a_ll)); // Calculating level 61.8
      lvl_78_6 = a_b_hh - ((78.6/100) * (a_b_hh - x_a_ll)); // Calculating level 78.6

      if((b_c_ll <= lvl_61_8 && b_c_ll >= lvl_78_6) && (D < x_a_ll))
        {

         //D
         ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
         ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
         ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
         ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
         ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

         //C
         ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_hh_t, c_d_hh); // Create text object for C
         ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
         ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
         ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_hh_t,C,time[c_highest_index+LookbackBars],c_d_hh); // Create line to mark C
         ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

         //B
         ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_ll_t, b_c_ll); // Create text object for B
         ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
         ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
         ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,time[b_lowest_index+LookbackBars],b_c_ll); // Create line to mark B
         ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

         //A
         ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_hh_t, a_b_hh); // Create text object for A
         ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
         ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
         ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,time[a_highest_index+LookbackBars],a_b_hh); // Create line to mark A
         ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

         //X
         ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_ll_t, x_a_ll); // Create text object for X
         ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
         ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,time[x_lowest_index+LookbackBars],x_a_ll); // Create line to mark X

         XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
         ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create line to connect XA
         ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
         ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

         AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
         ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); // Create line to connect AB
         ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
         ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

         BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
         ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); // Create line to connect BC
         ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
         ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

         CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
         ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_hh_t,c_d_hh,D_time,D); // Create line to connect CD
         ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
         ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

         //XA FIBO
         XA_fibo = StringFormat("XA FIB0 %d", i);
         ObjectCreate(chart_id,XA_fibo,OBJ_FIBO,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create XA fibo
         ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELS,6); // Number of default levels
         for(int i = 1; i <= 6; i++)
           {
            ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELCOLOR,i,clrSaddleBrown); // Set each level color to SaddleBrown
           }

         fibo_618_786 = StringFormat("Fibo 78.6 - 61.8 %d", i);
         fibo_78_6_txt = StringFormat("Fibo 78.6 Text %d", i);

         ObjectCreate(chart_id,fibo_618_786,OBJ_RECTANGLE,0,x_a_ll_t, lvl_61_8,b_c_ll_t,lvl_78_6); // Create rectangle object marking 61.8 and 78.6
         ObjectSetInteger(chart_id,fibo_618_786,OBJPROP_COLOR,clrSaddleBrown); // Set color to clrSaddleBrown

         ObjectCreate(chart_id,fibo_78_6_txt,OBJ_TEXT,0,b_c_ll_t,lvl_78_6); // Create text for level 78.6
         ObjectSetString(chart_id,fibo_78_6_txt,OBJPROP_TEXT,"78.6"); // Text to be displayed
         ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_COLOR,clrSaddleBrown); // Set text color
         ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_FONTSIZE,8); // Set text size

        }

      if(overlap == false)
        {
         i = m;
        }
      if(overlap == true)
        {
         i = i;
        }
      break;
     }
  }

出力

図12:BとX

説明

条件「if ((b_c_ll <= lvl_61_8 && b_c_ll >= lvl_78_6) && (D < x_a_ll))」がtrueと評価されることで、正しいハーモニックパターンが見つかった場合にのみ、すべてのチャートオブジェクトが描画されるようになります。これにより、誤ったパターンによってチャートが不要なオブジェクトで溢れてしまうのを防ぎます。この条件が満たされると、スクリプトは必要なすべての構成要素(フィボナッチリトレースメントレベル、X・A・B・C・Dを結ぶトレンドライン、そして各重要ポイントを示すテキストラベル)を作成・表示します。この方法により、インジケーターが正しく形成されたパターンのみを表示することが保証され、精度が向上し、視覚的にも明確で有用なチャート表示が保たれます。

2.3. 三角形XABとBCDの可視化

ハーモニックパターンをより視覚的に把握しやすくするため、このセクションではXABおよびBCDの構造を三角形としてチャート上に描画します。これらの三角形は視覚的な補助として機能し、パターンの構造を認識・分析する手助けとなります。

この可視化は、OBJ_TRIANGLEオブジェクトを使用して実現されます。最初の三角形はX、A、Bを結ぶことで構成され、二つ目の三角形はB、C、Dを結んで構成されます。XAB三角形はパターンの最初のレッグを強調し、X、A、Bの関係性を明確にします。一方でBCD三角形は最後のレッグを示し、Dポイント(すなわち、価格が反転する可能性のあるゾーン)へと至る構造を補強する形になります。

string X_A_B;
string B_C_D;
if((b_c_ll <= lvl_61_8 && b_c_ll >= lvl_78_6) && (D < x_a_ll))
  {

//D
   ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
   ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
   ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
   ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
   ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

//C
   ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_hh_t, c_d_hh); // Create text object for C
   ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
   ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
   ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_hh_t,C,time[c_highest_index+LookbackBars],c_d_hh); // Create line to mark C
   ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

//B
   ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_ll_t, b_c_ll); // Create text object for B
   ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
   ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
   ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,time[b_lowest_index+LookbackBars],b_c_ll); // Create line to mark B
   ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

//A
   ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_hh_t, a_b_hh); // Create text object for A
   ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
   ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
   ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,time[a_highest_index+LookbackBars],a_b_hh); // Create line to mark A
   ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

//X
   ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_ll_t, x_a_ll); // Create text object for X
   ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
   ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,time[x_lowest_index+LookbackBars],x_a_ll); // Create line to mark X

   XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
   ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create line to connect XA
   ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
   ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

   AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
   ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); // Create line to connect AB
   ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
   ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

   BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
   ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); // Create line to connect BC
   ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
   ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

   CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
   ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_hh_t,c_d_hh,D_time,D); // Create line to connect CD
   ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
   ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

//XA FIBO
   XA_fibo = StringFormat("XA FIB0 %d", i);
   ObjectCreate(chart_id,XA_fibo,OBJ_FIBO,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create XA fibo
   ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELS,6); // Number of default levels
   for(int i = 1; i <= 6; i++)
     {
      ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELCOLOR,i,clrSaddleBrown); // Set each level color to SaddleBrown
     }

   fibo_618_786 = StringFormat("Fibo 78.6 - 61.8 %d", i);
   fibo_78_6_txt = StringFormat("Fibo 78.6 Text %d", i);

   ObjectCreate(chart_id,fibo_618_786,OBJ_RECTANGLE,0,x_a_ll_t, lvl_61_8,b_c_ll_t,lvl_78_6); // Create rectangle object marking 61.8 and 78.6
   ObjectSetInteger(chart_id,fibo_618_786,OBJPROP_COLOR,clrSaddleBrown); // Set color to clrSaddleBrown

   ObjectCreate(chart_id,fibo_78_6_txt,OBJ_TEXT,0,b_c_ll_t,lvl_78_6); // Create text for level 78.6
   ObjectSetString(chart_id,fibo_78_6_txt,OBJPROP_TEXT,"78.6"); // Text to be displayed
   ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_COLOR,clrSaddleBrown); // Set text color
   ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_FONTSIZE,8); // Set text size

   X_A_B = StringFormat("XAB %d", i);
   ObjectCreate(chart_id,X_A_B,OBJ_TRIANGLE,0,x_a_ll_t,x_a_ll, a_b_hh_t, a_b_hh, b_c_ll_t, b_c_ll);
   ObjectSetInteger(chart_id,X_A_B,OBJPROP_COLOR,clrCornflowerBlue);
   ObjectSetInteger(chart_id,X_A_B,OBJPROP_FILL,true);

   B_C_D = StringFormat("BCD %d", i);
   ObjectCreate(chart_id,B_C_D,OBJ_TRIANGLE,0,b_c_ll_t,b_c_ll, c_d_hh_t, c_d_hh, D_time, D);
   ObjectSetInteger(chart_id,B_C_D,OBJPROP_COLOR,clrCornflowerBlue);
   ObjectSetInteger(chart_id,B_C_D,OBJPROP_FILL,true);
  }

出力

図13:強気パターン

説明

ハーモニックパターンのXABおよびBCDセグメントを構成する三角形には、それぞれ固有の名前が付けられており、それらは変数X_A_BおよびB_C_Dに格納されます。X_A_B三角形は、3つのポイントX、A、Bを使用して生成されます。これらのポイントは、それぞれの時刻と価格(x_a_ll_t、x_a_ll、a_b_hh_t、a_b_hh、b_c_ll_t、b_c_ll)によって識別されます。同様に、B_C_D三角形は、b_c_ll_t、b_c_ll、c_d_hh_t、c_d_hh、D_time、Dという3つのポイントB、C、Dを用いて構築されます。各三角形にはStringFormat関数を用いて一意の名前が付けられており、複数のパターンを描画する際にオブジェクト名の重複による問題を回避しています。

三角形がObjectCreate関数で生成された後には、ObjectSetInteger関数を使用してその視覚的属性が設定されます。OBJPROP_FILL属性をtrueに設定することで、輪郭線のみではなく中が塗りつぶされた三角形が描画されます。また、どちらの三角形にもコーンフラワーブルー色(clrCornflowerBlue)が適用されます。これらの視覚的要素は、パターン構造を迅速に特定し、取引チャンスを視認しやすくすることで、トレーダーの意思決定を支援します。

2.4. エントリーポイント、ストップロス、テイクプロフィットの表示

こちらのセクションでは、発見されたハーモニックパターンの重要な取引レベルを特定するために、エントリーポイント、ストップロス(SL)、およびテイクプロフィット(TP)を設定します。パターンの最も低いスイングローであるポイントDにストップロスを置きます。ハーモニックパターンは価格の反転を予測するため、ストップロスをDに設定することで、市場がこのレベルを超えて上昇した場合にパターンが無効となり、損失を最小限に抑えることができます。

エントリーポイントは、ポイントDのインデックスにLookbackBarsの半分を加えた位置に設定します。これは、ポイントDの確認後にわずかな遅れを設けて価格の動きを確認し、取引を行うためです。ポイントCは、予想される上昇前のスイングハイであるため、テイクプロフィットのレベルとして機能します。ストップロス、エントリー、テイクプロフィットの各レベルを示すラベルと水平線をチャート上に描画し、これらのレベルを視覚的に表示します。これにより、パターンに基づく取引において、トレーダーが取引設定を迅速に認識しやすくなります。

//Signal
string buy_txt;
string sell_txt;
string entry_line;
string tp_line;
string sl_line;
string tp_txt;
string sl_txt;
buy_txt = StringFormat("Buy %d", i);

ObjectCreate(chart_id,buy_txt,OBJ_TEXT,0,time[m + (LookbackBars / 2)],open[m  + (LookbackBars / 2)]);
ObjectSetString(chart_id,buy_txt,OBJPROP_TEXT,"BUY");
ObjectSetInteger(chart_id,buy_txt,OBJPROP_COLOR,clrCornflowerBlue);
ObjectSetInteger(chart_id,buy_txt,OBJPROP_FONTSIZE,10);

entry_line = StringFormat("Buy Entry Line %d", i);
ObjectCreate(chart_id,entry_line,OBJ_TREND,0,time[m  + (LookbackBars / 2)],open[m  + (LookbackBars / 2)], c_d_hh_t,open[m  + (LookbackBars / 2)]);
ObjectSetInteger(chart_id,entry_line,OBJPROP_WIDTH,3);
ObjectSetInteger(chart_id,entry_line,OBJPROP_COLOR,clrCornflowerBlue);

sl_txt = StringFormat("Buy SL %d", i);
ObjectCreate(chart_id,sl_txt,OBJ_TEXT,0,time[m + (LookbackBars / 2)],D);
ObjectSetString(chart_id,sl_txt,OBJPROP_TEXT,"SL");
ObjectSetInteger(chart_id,sl_txt,OBJPROP_COLOR,clrCornflowerBlue);
ObjectSetInteger(chart_id,sl_txt,OBJPROP_FONTSIZE,10);

sl_line = StringFormat("Buy SL Line %d", i);
ObjectCreate(chart_id,sl_line,OBJ_TREND,0,time[m + (LookbackBars / 2)],D,c_d_hh_t,D);
ObjectSetInteger(chart_id,sl_line,OBJPROP_WIDTH,3);
ObjectSetInteger(chart_id,sl_line,OBJPROP_COLOR,clrCornflowerBlue);

tp_txt = StringFormat("Buy TP %d", i);
ObjectCreate(chart_id,tp_txt,OBJ_TEXT,0,time[m +(LookbackBars / 2)],c_d_hh);
ObjectSetString(chart_id,tp_txt,OBJPROP_TEXT,"TP");
ObjectSetInteger(chart_id,tp_txt,OBJPROP_COLOR,clrCornflowerBlue);
ObjectSetInteger(chart_id,tp_txt,OBJPROP_FONTSIZE,10);

tp_line = StringFormat("Buy TP Line %d", i);
ObjectCreate(chart_id,tp_line,OBJ_TREND,0,time[m + (LookbackBars / 2)],c_d_hh,c_d_hh_t,c_d_hh);
ObjectSetInteger(chart_id,tp_line,OBJPROP_WIDTH,3);
ObjectSetInteger(chart_id,tp_line,OBJPROP_COLOR,clrCornflowerBlue);

出力

図14:シグナル

説明

このセクションでは、ハーモニックパターンにおける買いシグナル、エントリーポイント、ストップロス(SL)、およびテイクプロフィット(TP)のレベルが定義され、チャート上に視覚オブジェクトとして作成されます。チャート上でこれらの要素が簡単に管理・識別できるようにするため、buy_txt、sell_txt、entry_line、tp_line、sl_line、tp_txt、sl_txtの各変数には、それぞれのオブジェクトに固有の名前が格納されます。エントリーポイントには、buy_txtオブジェクトが「BUY」と表示されるテキストラベルとして配置され、取引の方向を示します。entry_lineは水平のトレンドラインであり、「open[m + (LookbackBars / 2)]」に位置するエントリープライスを示すことで、取引セットアップを明確に視覚化します。

同様に、ストップロスのラベルとその関連トレンドラインは、それぞれsl_txtとsl_lineによって表され、どちらもパターンの最も低いスイングローであるポイントDに配置されます。ストップロスは、価格がこの閾値を上回った場合に取引が無効になることを保証します。tp_txtおよびtp_lineは、直前のスイングハイであるc_d_hhに位置し、テイクプロフィットのレベルを示します。これらのグラフィカル要素には識別しやすい特徴的な色(clrCornflowerBlue)が設定されており、チャート上で重要な取引レベルを素早く認識することができます。これらのコンポーネントは、ハーモニックパターンに基づいた秩序立った透明性のある取引戦略の構築を支援します。


3. 弱気ハーモニックパターンの構築

同じロジックを、今度は弱気(下降)ハーモニックパターンに適用するために、本セクションではその内容を修正します。これは単に強気パターンの逆であるため、すべての機能を過度に強調する必要はありません。ここでは、スイングハイがX、スイングローがA、再びスイングハイがB、スイングローがC、そして最後のスイングハイがDとして表されます。これが主な違いです。この構成により、パターンが弱気な状況を正確に示し、売りのタイミングが近いことを示唆します。

Bポイントについては、引き続きXAレッグに対するフィボナッチリトレースメントを使用して、適切な範囲内にあるかどうかを確認します。同様に、パターンはトレンドラインや三角形などのチャート要素で視覚的に示されますが、それらの位置は弱気構造に合わせて調整されます。エントリーはDのインデックスにLookbackBarsの半分を加えた位置に設定され、テイクプロフィット(TP)はポイントC、ストップロス(SL)はポイントDに設定されます。これらは強気パターンの反対にすぎないため、ここでのロジックも同様であり、詳細な説明は繰り返しません。

int x_highest_index;   // Stores the index of the highest price point (X) in the pattern
double x_a_hh;         // Holds the price value of the swing high at point X
datetime x_a_hh_t;     // Stores the timestamp of when the swing high at X occurred

int a_lowest_index;   // Stores the index of the lowest price point (A) in the pattern
double a_b_ll;        // Holds the price value of the swing low at point A
datetime a_b_ll_t;    // Stores the timestamp of when the swing low at A occurred

int b_highest_index;   // Stores the index of the highest price point (B) in the pattern
double b_c_hh;         // Holds the price value of the swing high at point B
datetime b_c_hh_t;     // Stores the timestamp of when the swing high at B occurred
int c_lowest_index;   // Stores the index of the lowest price point (C) in the pattern
double c_d_ll;        // Holds the price value of the swing low at point C
datetime c_d_ll_t;    // Stores the timestamp of when the swing low at C occurred
if(rates_total >= bars_check)
  {
   for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
     {
      if(IsSwingHigh(high, i, LookbackBars))
        {

         X = high[i];                   // Assign the highest price at index 'i' to X
         X_time = time[i];              // Assign the corresponding time value to X_time
         X_line = StringFormat("XHigh%d", i);  // Create a unique string identifier for the X-high trendline
         X_letter = StringFormat("XB%d", i);   // Create a unique string identifier for the X-high label

         for(int j = i; j < rates_total - LookbackBars; j++)
           {
            if(IsSwingLow(low, j, LookbackBars) && time[j] > X_time)
              {
               A = low[j];                    // Assign the lowest price at index 'j' to A
               A_time = time[j];               // Assign the corresponding time value to A_time
               A_line = StringFormat("ALow%d", j);  // Create a unique string identifier for the A-low trendline
               A_letter = StringFormat("AB%d", j);  // Create a unique string identifier for the A-low label

               for(int k = j; k < rates_total - LookbackBars; k++)
                 {
                  if(IsSwingHigh(high, k, LookbackBars) && time[k] > A_time)
                    {

                     B = high[k];                    // Assign the highest price at index 'k' to B
                     B_time = time[k];                // Assign the corresponding time value to B_time
                     B_line = StringFormat("BHigh%d", k);  // Create a unique string identifier for the B-high trendline
                     B_letter = StringFormat("BB%d", k);   // Create a unique string identifier for the B-high label

                     for(int l = k; l < rates_total - LookbackBars; l++)
                       {
                        if(IsSwingLow(low, l, LookbackBars) && time[l] > B_time)
                          {

                           C = low[l];                      // Assign the lowest price at index 'l' to C
                           C_time = time[l];                // Assign the corresponding time value to C_time
                           C_line = StringFormat("CLow%d", l);  // Create a unique string identifier for the C-low trendline
                           C_letter = StringFormat("CB%d", l);   // Create a unique string identifier for the C-low label

                           for(int m = l; m < rates_total - (LookbackBars / 2); m++)
                             {
                              if(IsSwingHigh(high, m, LookbackBars / 2) && time[m] > C_time)
                                {
                                 D = high[m];                      // Assign the highest price at index 'm' to D
                                 D_time = time[m];                 // Assign the corresponding time value to D_time
                                 D_line = StringFormat("DHigh%d", m);  // Create a unique string identifier for the D-high trendline
                                 D_letter = StringFormat("DB%d", m);   // Create a unique string identifier for the D-high label

                                 // C - D Segment: Find the lowest low between C and D
                                 c_d_bars = Bars(_Symbol, PERIOD_CURRENT, C_time, D_time); // Count the number of bars between C and D
                                 c_lowest_index = ArrayMinimum(low, l, c_d_bars); // Find the index of the lowest low in the range

                                 c_d_ll = low[c_lowest_index]; // Store the lowest low (C - D lowest point)
                                 c_d_ll_t = time[c_lowest_index]; // Store the corresponding time for C - D

                                 // B - C Segment: Find the highest high between B and C
                                 b_c_bars = Bars(_Symbol, PERIOD_CURRENT, B_time, c_d_ll_t); // Count the number of bars between B and C
                                 b_highest_index = ArrayMaximum(high, k, b_c_bars); // Find the index of the highest high in the range

                                 b_c_hh = high[b_highest_index]; // Store the highest high (B - C highest point)
                                 b_c_hh_t = time[b_highest_index]; // Store the corresponding time for B - C

                                 // A - B Segment: Find the lowest low between A and B
                                 a_b_bars = Bars(_Symbol, PERIOD_CURRENT, A_time, b_c_hh_t); // Count the number of bars between A and B
                                 a_lowest_index = ArrayMinimum(low, j, a_b_bars); // Find the index of the lowest low in the range

                                 a_b_ll = low[a_lowest_index]; // Store the lowest low (A - B lowest point)
                                 a_b_ll_t = time[a_lowest_index]; // Store the corresponding time for A - B

                                 // X - A Segment: Find the highest high between X and A
                                 x_a_bars = Bars(_Symbol, PERIOD_CURRENT, X_time, a_b_ll_t); // Count the number of bars between X and A
                                 x_highest_index = ArrayMaximum(high, i, x_a_bars); // Find the index of the highest high in the range

                                 x_a_hh = high[x_highest_index]; // Store the highest high (X - A highest point)
                                 x_a_hh_t = time[x_highest_index]; // Store the corresponding time for X - A

                                 // Fibonacci Retracement Levels: Calculate 61.8% and 78.6% retracement levels from X to A
                                 lvl_61_8 = a_b_ll + ((61.8 / 100) * (x_a_hh - a_b_ll)); // 61.8% retracement level
                                 lvl_78_6 = a_b_ll + ((78.6 / 100) * (x_a_hh - a_b_ll)); // 78.6% retracement level

                                 if((b_c_hh >= lvl_61_8 && b_c_hh <= lvl_78_6) && (D > x_a_hh))
                                   {
                                    //D
                                    ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
                                    ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
                                    ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
                                    ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    //C
                                    ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_ll_t, c_d_ll); // Create text object for C
                                    ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
                                    ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_ll_t,C,time[c_lowest_index+LookbackBars],c_d_ll); // Create line to mark C
                                    ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    //B
                                    ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_hh_t, b_c_hh); // Create text object for B
                                    ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                                    ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_hh_t,b_c_hh,time[b_highest_index+LookbackBars],b_c_hh); // Create line to mark B
                                    ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

                                    //A
                                    ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_ll_t, a_b_ll); // Create text object for A
                                    ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                                    ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_ll_t,a_b_ll,time[a_lowest_index+LookbackBars],a_b_ll); // Create line to mark A
                                    ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                                    //X
                                    ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_hh_t, x_a_hh); // Create text object for X
                                    ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
                                    ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_hh_t,x_a_hh,time[x_highest_index+LookbackBars],x_a_hh); // Create line to mark X

                                    XA_line = StringFormat("XA LineB%d", m); // Unique name for the XA line.
                                    ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_hh_t,x_a_hh,a_b_ll_t,a_b_ll); // Create line to connect XA
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

                                    AB_line = StringFormat("AB LineB%d", m); // Unique name for the AB line.
                                    ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_ll_t,a_b_ll,b_c_hh_t,b_c_hh); // Create line to connect AB
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

                                    BC_line = StringFormat("BC LineB%d", m); // Unique name for the BC line.
                                    ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_hh_t,b_c_hh,c_d_ll_t,c_d_ll); // Create line to connect BC
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

                                    CD_line = StringFormat("CD LineB%d", m); // Unique name for the CD line.
                                    ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_ll_t,c_d_ll,D_time,D); // Create line to connect CD
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

                                    //XA FIBO
                                    XA_fibo = StringFormat("XA FIB0 B%d", i);
                                    ObjectCreate(chart_id,XA_fibo,OBJ_FIBO,0,x_a_hh_t,x_a_hh,a_b_ll_t,a_b_ll); // Create XA fibo
                                    ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELS,6); // Number of default levels
                                    for(int i = 1; i <= 6; i++)
                                      {
                                       ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELCOLOR,i,clrSaddleBrown); // Set each level color to SaddleBrown
                                      }

                                    fibo_618_786 = StringFormat("Fibo 78.6 - 61.8 B%d", i);
                                    fibo_78_6_txt = StringFormat("Fibo 78.6 Text B%d", i);

                                    ObjectCreate(chart_id,fibo_618_786,OBJ_RECTANGLE,0,x_a_hh_t, lvl_61_8,b_c_hh_t,lvl_78_6); // Create rectangle object marking 61.8 and 78.6
                                    ObjectSetInteger(chart_id,fibo_618_786,OBJPROP_COLOR,clrSaddleBrown); // Set color to clrSaddleBrown

                                    ObjectCreate(chart_id,fibo_78_6_txt,OBJ_TEXT,0,b_c_hh_t,lvl_78_6); // Create text for level 78.6
                                    ObjectSetString(chart_id,fibo_78_6_txt,OBJPROP_TEXT,"78.6"); // Text to be displayed
                                    ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_COLOR,clrSaddleBrown); // Set text color
                                    ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_FONTSIZE,8); // Set text size
                                    // Create and format the first bearish harmonic pattern (XAB)
                                    X_A_B = StringFormat("XAB B%d", i);
                                    ObjectCreate(chart_id, X_A_B, OBJ_TRIANGLE, 0, x_a_hh_t, x_a_hh, a_b_ll_t, a_b_ll, b_c_hh_t, b_c_hh);
                                    ObjectSetInteger(chart_id, X_A_B, OBJPROP_COLOR, clrMistyRose); // Set color for the pattern
                                    ObjectSetInteger(chart_id, X_A_B, OBJPROP_FILL, true); // Fill the triangle shape

                                    // Create and format the second bearish harmonic pattern (BCD)
                                    B_C_D = StringFormat("BCD B%d", i);
                                    ObjectCreate(chart_id, B_C_D, OBJ_TRIANGLE, 0, b_c_hh_t, b_c_hh, c_d_ll_t, c_d_ll, D_time, D);
                                    ObjectSetInteger(chart_id, B_C_D, OBJPROP_COLOR, clrMistyRose);
                                    ObjectSetInteger(chart_id, B_C_D, OBJPROP_FILL, true);

                                    // Create and format the SELL text at the entry position
                                    sell_txt = StringFormat("Sell %d", i);
                                    ObjectCreate(chart_id, sell_txt, OBJ_TEXT, 0, time[m + (LookbackBars / 2)], open[m + (LookbackBars / 2)]);
                                    ObjectSetString(chart_id, sell_txt, OBJPROP_TEXT, "SELL");
                                    ObjectSetInteger(chart_id, sell_txt, OBJPROP_COLOR, clrMagenta); // Set text color
                                    ObjectSetInteger(chart_id, sell_txt, OBJPROP_FONTSIZE, 10); // Set font size

                                    // Create and format the SELL entry line
                                    entry_line = StringFormat("Sell Entry Line %d", i);
                                    ObjectCreate(chart_id, entry_line, OBJ_TREND, 0, time[m + (LookbackBars / 2)], open[m + (LookbackBars / 2)], c_d_ll_t, open[m + (LookbackBars / 2)]);
                                    ObjectSetInteger(chart_id, entry_line, OBJPROP_WIDTH, 3); // Set line thickness
                                    ObjectSetInteger(chart_id, entry_line, OBJPROP_COLOR, clrMagenta); // Set line color

                                    // Create and format the Stop Loss (SL) text
                                    sl_txt = StringFormat("Sell SL %d", i);
                                    ObjectCreate(chart_id, sl_txt, OBJ_TEXT, 0, time[m + (LookbackBars / 2)], D);
                                    ObjectSetString(chart_id, sl_txt, OBJPROP_TEXT, "SL");
                                    ObjectSetInteger(chart_id, sl_txt, OBJPROP_COLOR, clrMagenta);
                                    ObjectSetInteger(chart_id, sl_txt, OBJPROP_FONTSIZE, 10);

                                    // Create and format the Stop Loss (SL) line
                                    sl_line = StringFormat("Sell SL Line %d", i);
                                    ObjectCreate(chart_id, sl_line, OBJ_TREND, 0, time[m + (LookbackBars / 2)], D, c_d_ll_t, D);
                                    ObjectSetInteger(chart_id, sl_line, OBJPROP_WIDTH, 3);
                                    ObjectSetInteger(chart_id, sl_line, OBJPROP_COLOR, clrMagenta);

                                    // Create and format the Take Profit (TP) text
                                    tp_txt = StringFormat("Sell TP %d", i);
                                    ObjectCreate(chart_id, tp_txt, OBJ_TEXT, 0, time[m + (LookbackBars / 2)], c_d_ll);
                                    ObjectSetString(chart_id, tp_txt, OBJPROP_TEXT, "TP");
                                    ObjectSetInteger(chart_id, tp_txt, OBJPROP_COLOR, clrMagenta);
                                    ObjectSetInteger(chart_id, tp_txt, OBJPROP_FONTSIZE, 10);

                                    // Create and format the Take Profit (TP) line
                                    tp_line = StringFormat("Sell TP Line %d", i);
                                    ObjectCreate(chart_id, tp_line, OBJ_TREND, 0, time[m + (LookbackBars / 2)], c_d_ll, c_d_ll_t, c_d_ll);
                                    ObjectSetInteger(chart_id, tp_line, OBJPROP_WIDTH, 3);
                                    ObjectSetInteger(chart_id, tp_line, OBJPROP_COLOR, clrMagenta);

                                    if(overlap == false)
                                      {
                                       i = m;
                                      }
                                    if(overlap == true)
                                      {
                                       i = i;
                                      }
                                    break;

                                   }

                                 break;

                                }
                             }

                           break;

                          }
                       }

                     break;

                    }
                 }

               break;

              }
           }

        }
     }
  }

出力

図15:弱気パターン

説明

パターンの始点を示すスイングハイXを見つけることが、検出プロセスの最初のステップです。次に、スイングロー(A)、スイングハイ(B)、スイングロー(C)、そして最後にスイングハイ(D)を順に探します。各ポイントが直前のポイントとの相対的な位置関係に従っていることを確認することで、正当なパターン構造が保証されます。パターンの妥当性を判断する上で最も重要なのは、XからAにかけてのリトレースメントレベル、とくに61.8%および78.6%のフィボナッチリトレースメントです。これらの条件が満たされ、かつDがある程度の水準以上である場合、売りの可能性があるパターン(SELL構成)が検出されます。

弱気と強気のハーモニックパターンは非常に似ているため、詳細な説明は繰り返しません。主な違いは、ブルリッシュパターンが価格の上昇を予測するのに対し、こちらのパターンは価格の下落を予測するという点です。パターンの向きと、それに伴う取引の方向が異なるだけで、それ以外の基本的な考え方は同じです。


結論

本記事では、MetaTrader 5のチャートオブジェクトを用いて、ハーモニックパターンのようなインジケーターを構築する方法を解説しました。主要なスイングポイントの検出ロジック、パターンの構成方法、そしてフィボナッチリトレースメントレベルを用いた検証手順について取り上げました。強気と弱気の両パターンを実装することで、プライスアクションに基づく潜在的な取引機会をどのように特定するかを示しました。このアプローチを使えば、ハーモニックパターンをチャート上に直接視覚化することができ、従来のインジケーターバッファに依存せず、より的確な判断が可能になります。この手法は柔軟性を高め、パターンベースの取引戦略をさらにカスタマイズ・洗練させていくための堅実な基盤を提供します。

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/17574

最後のコメント | ディスカッションに移動 (6)
Israel Pelumi Abioye
Israel Pelumi Abioye | 1 4月 2025 において 12:03
Simon Simson #:
このMQL5シリーズを よくやってくれて本当にありがとう。
サイモンさん、こんにちは。
ありがたいお言葉をありがとうございます。
Oluwatosin Mary Babalola
Oluwatosin Mary Babalola | 1 4月 2025 において 12:15
ワオ、これは私があなたの記事を見て以来、これまでで最高だ。これからも頑張って
Israel Pelumi Abioye
Israel Pelumi Abioye | 1 4月 2025 において 13:02
Oluwatosin Mary Babalola #:
ワオ、これは私があなたの記事を見て以来、これまでで最高だ。これからも頑張って
ありがとう。
Louai Habiche
Louai Habiche | 19 4月 2025 において 17:03

素晴らしい。

私達はsihnalショーがあるとき警報に置くことができる!

Israel Pelumi Abioye
Israel Pelumi Abioye | 20 4月 2025 において 10:37
Louai Habiche #:

素晴らしい。

私達はsihnalショーがあるとき警報に置くことができる!

PlaySound()」関数を使えば可能です。

デイトレードLarry Connors RSI2平均回帰戦略 デイトレードLarry Connors RSI2平均回帰戦略
Larry Connorsは著名なトレーダー兼著者であり、特に2期間RSI (RSI2)などのクオンツトレーディングや戦略で知られています。RSI2は短期的な買われすぎ・売られすぎの市場状況を識別するのに役立ちます。本記事では、まず私たちの研究の動機を説明し、その後Connorsの代表的な3つの戦略をMQL5で再現し、S&P 500指数CFDのデイトレードに適用していきます。
MQL5で自己最適化エキスパートアドバイザーを構築する(第6回):自己適応型取引ルール(II) MQL5で自己最適化エキスパートアドバイザーを構築する(第6回):自己適応型取引ルール(II)
本記事では、より良い売買シグナルを得るために、RSIのレベルと期間を最適化する方法を探ります。最適なRSI値を推定する手法や、グリッドサーチと統計モデルを用いた期間選定の自動化について紹介します。最後に、Pythonによる分析を活用しながら、MQL5でソリューションを実装します。私たちのアプローチは、複雑になりがちな問題をシンプルに解決することを目指した、実用的かつ分かりやすいものです。
知っておくべきMQL5ウィザードのテクニック(第58回):移動平均と確率的オシレーターパターンを用いた強化学習(DDPG) 知っておくべきMQL5ウィザードのテクニック(第58回):移動平均と確率的オシレーターパターンを用いた強化学習(DDPG)
移動平均とストキャスティクスはよく使われるインジケーターで、前回の記事ではこの2つの組み合わせパターンを教師あり学習ネットワークで分析して、どのパターンが使えそうかを確認しました。今回はそこから一歩進めて、訓練済みネットワークに強化学習を組み合わせたらパフォーマンスにどんな影響があるかを見ていきます。テスト期間はかなり短いので、その点は踏まえておいてください。とはいえ、今回もMQL5ウィザードのおかげで、コード量はかなり少なくて済んでいます。
MQL5での取引戦略の自動化(第12回):Mitigation Order Blocks (MOB)戦略の実装 MQL5での取引戦略の自動化(第12回):Mitigation Order Blocks (MOB)戦略の実装
本記事では、スマートマネー取引向けにオーダーブロックの自動検出をおこなうMQL5取引システムを構築します。戦略のルールを明確にし、そのロジックをMQL5で実装し、さらに取引を効果的に執行するためにリスク管理も統合します。最後に、システムのパフォーマンスを評価するためにバックテストをおこない、最適な結果を得るための改良を加えます。