ローソク足分析技術の研究(第3部): パターン操作のライブラリ

Alexander Fedosov | 18 7月, 2019

目次

はじめに

ローソク足分析の手法についてはすでに検討しました。現在の市場状況下でのパターンの実際性は第1部で確認され、これらの研究を拡大する試みは第2部で行われました。開発評価基準を用いて、広範囲の可能なパターンの組み合わせが研究され、テストされ、比較されました。この目的のために、パターンを研究するための多数の設定を備えたカスタムパターンアナライザアプリケーションが開発されました。しかしながら、理論と研究は情報と結論を提供することしかできません。タスクの論理的な継続は、実際の状況での使用です。

本稿の目的は、カスタムツールを作成して、前述のパターンに関する一連の情報全体を受信して使用できるようにすることです。ユーザが独自の指標、取引パネル、エキスパートアドバイザーなどで使用できるライブラリが作成されます。    


ライブラリの構造

ライブラリ構造、クラス、接続の作成に進む前に、使用するデータを定義しましょう。つまり、入力データを担当するメソッドと結果を提供するメソッドを分離する必要があります。一般的なライブラリ構造は、以前の記事で開発されたビジュアルソリューションであるパターンアナライザに基づいています。 

パターンをテストするときに結果に影響を与える可能性があるアプリケーション入力データから始めましょう。

図1 [設定]タブの入力パラメータ

ブロック1 既存のパターンと生成されたパターンを構成するローソク足のタイプのリストを特徴としています。それぞれのタイプには設定があり、ローソク足の視覚化ページの右上隅にある歯車のアイコンをクリックすると表示できます。ローソク足タイプ1〜5には1つの設定しかありませんが、「唐笠」には2つの設定があります。 

ブロック2 重み係数。パターン効率評価結果に影響を与える3つのパラメータК1、К2、К3があります。 

ブロック3 ポイント単位のトレンド閾値。 

ブロック4 生成されたパターンのテストに使用されるローソク足。ここでは、シーケンス番号またはローソク足インデックスが必要になります。このデータを使用して、最大3つのローソク足まで、任意のサイズの任意のパターンに関する情報を取得できます。

ブロック5 パターンの中のローソク足数。この設定は、カスタムパターンにのみ適用されます。 

[分析]タブとそこに含まれている入力パラメータを見てみましょう。

図2 [分析]タブの入力パラメータ

ブロック6 パターン解析に使用される現在の時間枠とデータサンプル範囲の設定が含まれています。 

ブロック7 既存パターンの名前。パターンにアクセスしてそれに関する情報を取得するために必要であるがアプリケーションからは編集できない入力もあります。

ここでパターン分析から得られるデータを列挙しましょう。これは、クラス内でメソッドの正しい構造を作成するために必要です。

ライブラリの開発

基本的なポイントを決めたら、ライブラリの作成に進みましょう。必要な列挙体を持つファイルEnums.mqhの作成から始めましょう。

//+------------------------------------------------------------------+
//|                                                        Enums.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                           https://www.mql5.com/ja/users/alex2356 |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| ローソク足タイプ                                                   |
//+------------------------------------------------------------------+
enum TYPE_CANDLESTICK
  {
   CAND_NONE,           // 未定義
   CAND_MARIBOZU,       // 丸坊主
   CAND_DOJI,           // 同事
   CAND_SPIN_TOP,       // コマ(極線)
   CAND_HAMMER,         // 唐笠
   CAND_INVERT_HAMMER,  // トンカチ
   CAND_LONG,           // ロング
   CAND_SHORT           // ショート
  };
//+------------------------------------------------------------------+
//| パターンタイプ                                                     |
//+------------------------------------------------------------------+
enum TYPE_PATTERN
  {
   NONE,
   HUMMER,
   INVERT_HUMMER,
   HANDING_MAN,
   SHOOTING_STAR,
   ENGULFING_BULL,
   ENGULFING_BEAR,
   HARAMI_BULL,
   HARAMI_BEAR,
   HARAMI_CROSS_BULL,
   HARAMI_CROSS_BEAR,
   DOJI_STAR_BULL,
   DOJI_STAR_BEAR,
   PIERCING_LINE,
   DARK_CLOUD_COVER
  };
//+------------------------------------------------------------------+
//| トレンドタイプ                                                     |
//+------------------------------------------------------------------+
enum TYPE_TREND
  {
   UPPER,               // 上昇
   DOWN,                // 下降
   FLAT                 // フラット
  };
//+------------------------------------------------------------------+

ここでは、使用されている単純なローソク足の種類、既存のパターンの種類、トレンドタイプの一覧を決定します。データは、チャート上の既存のパターンを識別するために必要です。

その後、Pattern.mqhファイルを作成します。CPatternクラスがその中に作成され、そのプライベートセクションで前のセクションで述べたパラメータの変数を宣言します。ファイルを列挙とリンクすることも必要です。

//+------------------------------------------------------------------+
//|                                                      Pattern.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                           https://www.mql5.com/ja/users/alex2356 |
//+------------------------------------------------------------------+
#include "Enums.mqh"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CPattern
  {
private:
   //--- 重み
   double            m_k1;
   double            m_k2;
   double            m_k3;
   //--- ポイント単位のトレンド閾値
   int               m_threshold_value;
   //--- ロングローソク足設定係数
   double            m_long_coef;
   //--- ショートローソク足設定係数
   double            m_short_coef;
   //--- 同事ローソク足設定係数
   double            m_doji_coef;
   //--- 丸坊主ローソク足設定係数
   double            m_maribozu_coef;
   //--- コマ(極線)ローソク足設定係数
   double            m_spin_coef;
   //--- 唐笠ローソク足設定係数
   double            m_hummer_coef1;
   double            m_hummer_coef2;
   //--- プリセットパターンのサンプリング範囲
   int               m_range_total;
   //--- トレンドを特定する期間
   int               m_trend_period;
   //--- 見つかったパターン
   int               m_found;
   //--- パターンの発生
   double            m_coincidence;
   //--- 上向きまたは下向きの動きの確率
   double            m_probability1;
   double            m_probability2;
   //--- 効率
   double            m_efficiency1;
   double            m_efficiency2;
   //--- 単純なローソク足パターン
   struct CANDLE_STRUCTURE
     {
      double            m_open;
      double            m_high;
      double            m_low;
      double            m_close;                      // OHLC
      TYPE_TREND        m_trend;                      // トレンド
      bool              m_bull;                       // 強気ローソク足
      double            m_bodysize;                   // 実体サイズ
      TYPE_CANDLESTICK  m_type;                       // ローソク足タイプ
     };
   //--- パターン効率評価プロパティ
   struct RATING_SET
     {
      int               m_a_uptrend;
      int               m_b_uptrend;
      int               m_c_uptrend;
      int               m_a_dntrend;
      int               m_b_dntrend;
      int               m_c_dntrend;
     };

上記のコードからわかるように、2つの構造体がプログラムに追加されました。最初のCANDLE_STRUCTURE構造体は、チャートのローソク足の種類を特定するために必要です。この構造体では、以前に考慮されこの構造体用に作成されたEnums.mqhファイルからのTYPE_TRENDおよびTYPE_CANDLESTICKの2種類のトレンド列挙が使用されていることにご注意ください。2番目のRATING_SET構造体には、パターンの出現後の価格変動予測の記録が格納されています。詳細は第1部をご覧ください。

ここで、ライブラリ構造の節で説明されているクラスのpublicセクションの一部について考えてみましょう。ここでは、入力パラメータの値をカスタマイズおよび取得するためのメソッドが説明されます。

public:
                     CPattern(void);
                    ~CPattern(void);
   //--- 重み係数を設定し返す
   void              K1(const double k1)                             { m_k1=k1;                       }
   double            K1(void)                                        { return(m_k1);                  }
   void              K2(const double k2)                             { m_k2=k2;                       }
   double            K2(void)                                        { return(m_k2);                  }
   void              K3(const double k3)                             { m_k3=k3;                       }
   double            K3(void)                                        { return(m_k3);                  }
   //--- トレンド閾値を設定して返す
   void              Threshold(const int threshold)                  { m_threshold_value=threshold;   }
   int               Threshold(void)                                 { return(m_threshold_value);     }
   //--- ロングローソク足設定係数を設定して返す
   void              Long_coef(const double long_coef)               { m_long_coef=long_coef;         }
   double            Long_coef(void)                                 { return(m_long_coef);           }
   //--- ショートローソク足設定係数を設定して返す
   void              Short_coef(const double short_coef)             { m_short_coef=short_coef;       }
   double            Short_coef(void)                                { return(m_short_coef);          }
   //--- 同事ローソク足設定係数を設定して返す
   void              Doji_coef(const double doji_coef)               { m_doji_coef=doji_coef;         }
   double            Doji_coef(void)                                 { return(m_doji_coef);           }
   //--- 丸坊主ローソク足設定係数を設定して返す
   void              Maribozu_coef(const double maribozu_coef)       { m_maribozu_coef=maribozu_coef; }
   double            Maribozu_coef(void)                             { return(m_maribozu_coef);       }
   //--- コマ(極線)ローソク足設定係数を設定して返す
   void              Spin_coef(const double spin_coef)               { m_spin_coef=spin_coef;         }
   double            Spin_coef(void)                                 { return(m_spin_coef);           }
   //--- 唐笠ローソク足設定係数を設定して返す
   void              Hummer_coef1(const double hummer_coef1)         { m_hummer_coef1=hummer_coef1;   }
   void              Hummer_coef2(const double hummer_coef2)         { m_hummer_coef2=hummer_coef2;   }
   double            Hummer_coef1(void)                              { return(m_hummer_coef1);        }
   double            Hummer_coef2(void)                              { return(m_hummer_coef2);        }
   //--- プリセットパラメータのサンプリング範囲を設定して返す
   void              Range(const int range_total)                    { m_range_total=range_total;     }
   int               Range(void)                                     { return(m_range_total);         }
   //--- トレンド計算用のローソク足の数を設定して返す  
   void              TrendPeriod(const int period)                   { m_trend_period=period;         }
   int               TrendPeriod(void)                               { return(m_trend_period);        }

クラスコンストラクタでは、アプリケーションの[設定]タブで指定されているデフォルトパラメーターを説明します。

//+------------------------------------------------------------------+
//| コンストラクタ                                                     |
//+------------------------------------------------------------------+
CPattern::CPattern(void) : m_k1(1),
                           m_k2(0.5),
                           m_k3(0.25),
                           m_threshold_value(100),
                           m_long_coef(1.3),
                           m_short_coef(0.5),
                           m_doji_coef(0.04),
                           m_maribozu_coef(0.01),
                           m_spin_coef(1),
                           m_hummer_coef1(0.1),
                           m_hummer_coef2(2),
                           m_range_total(8000),
                           m_trend_period(5)
  {
  }

CPatternクラスのパブリックセクションの2番目の部分では、宣言された入力パラメータの処理方法とパターンのプロパティと特性の取得方法について説明します。

それぞれを詳しく見てみましょう。指標、取引パネル、エキスパートアドバイザーを作成するときに効率的に使用できるようにするためには、操作アルゴリズムを理解することが重要です。

CandleType

TYPE_CANDLESTICKにリストされている既存のパターンから選択されたローソク足のタイプを返します。
TYPE_CANDLESTICK  CandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,const int shift);

パラメータ

戻り値

選択されたローソク足のTYPE_CANDLESTICK列挙からの種類

//+------------------------------------------------------------------+
//| ローソク足タイプ                                                   |
//+------------------------------------------------------------------+
enum TYPE_CANDLESTICK
  {
   CAND_NONE,           // 未定義
   CAND_MARIBOZU,       // 丸坊主
   CAND_DOJI,           // 同事
   CAND_SPIN_TOP,       // コマ(極線)
   CAND_HAMMER,         // 唐笠
   CAND_INVERT_HAMMER,  // トンカチ
   CAND_LONG,           // ロング
   CAND_SHORT           // ショート
  };

実装

//+------------------------------------------------------------------+
//| 選択されたローソク足の種類を返す                                     |
//+------------------------------------------------------------------+
TYPE_CANDLESTICK CPattern::CandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,const int shift)
  {
   CANDLE_STRUCTURE res;
   if(GetCandleType(symbol,timeframe,res,shift))
      return(res.m_type);
   return(CAND_NONE);
  }
//+------------------------------------------------------------------+
//| ローソク足タイプの特定                                              |
//+------------------------------------------------------------------+
bool CPattern::GetCandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,CANDLE_STRUCTURE &res,const int shift)
  {
   MqlRates rt[];
   int aver_period=m_trend_period;
   double aver=0;
   SymbolSelect(symbol,true);
   int copied=CopyRates(symbol,timeframe,shift,aver_period+1,rt);
//--- 1つ前のローソク足の詳細を取得する
   if(copied<aver_period)
      return(false);
//---
   res.m_open=rt[aver_period].open;
   res.m_high=rt[aver_period].high;
   res.m_low=rt[aver_period].low;
   res.m_close=rt[aver_period].close;

//--- トレンド方向を特定する
   for(int i=0;i<aver_period;i++)
      aver+=rt[i].close;
   aver/=aver_period;

   if(aver<res.m_close)
      res.m_trend=UPPER;
   if(aver>res.m_close)
      res.m_trend=DOWN;
   if(aver==res.m_close)
      res.m_trend=FLAT;
//--- ローソク足が強気か弱気かを特定する
   res.m_bull=res.m_open<res.m_close;
//--- ローソク足実体サイズの絶対的なサイズを取得する
   res.m_bodysize=MathAbs(res.m_open-res.m_close);
//--- 髭のサイズを取得する
   double shade_low=res.m_close-res.m_low;
   double shade_high=res.m_high-res.m_open;
   if(res.m_bull)
     {
      shade_low=res.m_open-res.m_low;
      shade_high=res.m_high-res.m_close;
     }
   double HL=res.m_high-res.m_low;
//--- 以前のローソク足の平均実体サイズを計算する
   double sum=0;
   for(int i=1; i<=aver_period; i++)
      sum=sum+MathAbs(rt[i].open-rt[i].close);
   sum=sum/aver_period;

//--- ローソク足のタイプを特定する   
   res.m_type=CAND_NONE;
//--- 長い 
   if(res.m_bodysize>sum*m_long_coef)
      res.m_type=CAND_LONG;
//--- 短い 
   if(res.m_bodysize<sum*m_short_coef)
      res.m_type=CAND_SHORT;
//--- 同事
   if(res.m_bodysize<HL*m_doji_coef)
      res.m_type=CAND_DOJI;
//--- 丸坊主
   if((shade_low<res.m_bodysize*m_maribozu_coef || shade_high<res.m_bodysize*m_maribozu_coef) && res.m_bodysize>0)
      res.m_type=CAND_MARIBOZU;
//--- 唐笠
   if(shade_low>res.m_bodysize*m_hummer_coef2 && shade_high<res.m_bodysize*m_hummer_coef1)
      res.m_type=CAND_HAMMER;
//--- トンカチ
   if(shade_low<res.m_bodysize*m_hummer_coef1 && shade_high>res.m_bodysize*m_hummer_coef2)
      res.m_type=CAND_INVERT_HAMMER;
//--- コマ(極線)
   if(res.m_type==CAND_SHORT && shade_low>res.m_bodysize*m_spin_coef && shade_high>res.m_bodysize*m_spin_coef)
      res.m_type=CAND_SPIN_TOP;
//---
   ArrayFree(rt);
   return(true);
  }

ローソク足認識メソッドGetCandleType()はpublicのGetCandleType()メソッドで使用されます。GetCandleType()はprivateメソッドです。その引数には、現在の銘柄、時間枠、ローソク足の番号、構造体へのポインタが含まれます。これらのパラメータに基づいてパターンの計算と識別が行われます。

PatternType

選択したローソク足でパターンの種類を認識します。引数は、TYPE_PATTERN列挙体からの既存のパターン、または1つ、2つ、または3つのローソク足で構成される生成されたパターンのいずれかである可能性があるため、5つのメソッドがオーバーロードされます。引数は、TYPE_PATTERN列挙からのパターンの配列にすることもできます。

   //--- パターンタイプの認識
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,int shift);
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,const int shift);
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,const int shift);
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,const int shift);
   //--- パターンセットの認識
   bool              PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN &pattern[],int shift);

パラメータ

TYPE_PATTERNリストからの既存パターンの配列へのポインタ。

//+------------------------------------------------------------------+
//| パターンタイプ                                                     |
//+------------------------------------------------------------------+
enum TYPE_PATTERN
  {
   NONE,
   HUMMER,
   INVERT_HUMMER,
   HANDING_MAN,
   SHOOTING_STAR,
   ENGULFING_BULL,
   ENGULFING_BEAR,
   HARAMI_BULL,
   HARAMI_BEAR,
   HARAMI_CROSS_BULL,
   HARAMI_CROSS_BEAR,
   DOJI_STAR_BULL,
   DOJI_STAR_BEAR,
   PIERCING_LINE,
   DARK_CLOUD_COVER
  };

戻り値

ブール値

実装

5種類のPatternTypeメソッドの実装があるため、さまざまな引数を使用して個別に分析します。最初のものは、TYPE_PATTERN列挙から既存のパターンを検索します。以下でわかるように、これはプライベートメソッドCheckPatternを使って行われます。

//+------------------------------------------------------------------+
//| 定義済みパターンの認識                                              |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,const int shift)
  {
   if(CheckPattern(symbol,timeframe,shift)==pattern)
      return(true);
   return(false);
  }
//+------------------------------------------------------------------+
//| パターンタイプを確認して返す                                         |
//+------------------------------------------------------------------+
TYPE_PATTERN CPattern::CheckPattern(const string symbol,const ENUM_TIMEFRAMES timeframe,int shift)
  {
   CANDLE_STRUCTURE cand1,cand2;
   TYPE_PATTERN pattern=NONE;
   ZeroMemory(cand1);
   ZeroMemory(cand2);
   GetCandleType(symbol,timeframe,cand2,shift);                                           // 1つ前のローソク足
   GetCandleType(symbol,timeframe,cand1,shift-1);                                         // 現在のローソク足
//--- トンカチ(強気)
   if(cand2.m_trend==DOWN &&                                                              // トレンド方向の確認
      cand2.m_type==CAND_INVERT_HAMMER)                                                   // 「トンカチ」の確認
      pattern=INVERT_HUMMER;
//--- 首吊り(弱気)
   else if(cand2.m_trend==UPPER && // トレンド方向の確認
      cand2.m_type==CAND_HAMMER) // 「唐笠」の確認
      pattern=HANDING_MAN;
//--- 唐笠(強気)
   else if(cand2.m_trend==DOWN && // トレンド方向の確認
      cand2.m_type==CAND_HAMMER) // 「唐笠」の確認
      pattern=HUMMER;
//--- 流れ星(弱気)
   else if(cand1.m_trend==UPPER && cand2.m_trend==UPPER && // トレンド方向の確認
      cand2.m_type==CAND_INVERT_HAMMER && cand1.m_close<=cand2.m_open) // 「トンカチ」の確認
      pattern=SHOOTING_STAR;
//--- 抱き線(包み線)(強気)
   else if(cand1.m_trend==DOWN && cand1.m_bull && cand2.m_trend==DOWN && !cand2.m_bull && // トレンドとローソク足方向の確認
      cand1.m_bodysize>cand2.m_bodysize &&
      cand1.m_close>=cand2.m_open && cand1.m_open<cand2.m_close)
      pattern=ENGULFING_BULL;
//--- 抱き線(包み線)(弱気)
   else if(cand1.m_trend==UPPER && cand1.m_bull && cand2.m_trend==UPPER && !cand2.m_bull && // トレンドとローソク足方向の確認
      cand1.m_bodysize<cand2.m_bodysize &&
      cand1.m_close<=cand2.m_open && cand1.m_open>cand2.m_close)
      pattern=ENGULFING_BEAR;
//--- Harami Cross(はらみ交差)(強気)
   else if(cand2.m_trend==DOWN && !cand2.m_bull && // トレンドとローソク足方向の確認
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // Checking the "long" first candlestick and the doji candlestick
      cand1.m_close<cand2.m_open && cand1.m_open>=cand2.m_close) // 「同事」が1番目のローソク足の実体の内側にある
      pattern=HARAMI_CROSS_BULL;
//--- Harami Cross(はらみ交差)(弱気)
   else if(cand2.m_trend==UPPER && cand2.m_bull && // トレンドとローソク足方向の確認
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // 「ロング」ローソク足と同事ローソク足の確認
      cand1.m_close>cand2.m_open && cand1.m_open<=cand2.m_close) // 「同事」が1番目のローソク足の実体の内側にある
      pattern=HARAMI_CROSS_BEAR;
//--- はらみ(強気)
   else if(cand1.m_trend==DOWN && cand1.m_bull && !cand2.m_bull && // トレンドとローソク足の方向の確認
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // 「ロング」1番目のローソク足の確認
      cand1.m_type!=CAND_DOJI && cand1.m_bodysize<cand2.m_bodysize && // 2番目のローソク足は同事ではなく、1つ目のローソク足の実体は2つ目のローソク足よりも大きい
                    cand1.m_close<cand2.m_open && cand1.m_open>=cand2.m_close) // 2番目のローソク足の実態が1番目のローソク足の実体の内側にある
                    pattern=HARAMI_BULL;
//--- はらみ(弱気)
   else if(cand1.m_trend==UPPER && !cand1.m_bull && cand2.m_bull && // トレンドとローソク足の方向の確認
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // 「ロング」1番目のローソク足の確認

      cand1.m_type!=CAND_DOJI && cand1.m_bodysize<cand2.m_bodysize && // 2番目のローソク足は同事ではなく、1つ目のローソク足の実体は2つ目のローソク足よりも大きい
                    cand1.m_close>cand2.m_open && cand1.m_open<=cand2.m_close) // 2番目のローソク足の実態が1番目のローソク足の実体の内側にある
                    pattern=HARAMI_BEAR;
//--- Doji Star(同事星)(強気)
   else if(cand1.m_trend==DOWN && !cand2.m_bull && // トレンドとローソク足の方向の確認
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // 1番目の「ロング」ローソク足と2番目の同事ローソク足の確認
      cand1.m_close<=cand2.m_open) // 同事の始値が1番目のローソク足の終値以下
      pattern=DOJI_STAR_BULL;
//--- Doji Star(同事星)(弱気)
   else if(cand1.m_trend==UPPER && cand2.m_bull && // トレンドとローソク足の方向の確認
      (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // 1番目の「ロング」ローソク足と2番目の同事ローソク足の確認
      cand1.m_open>=cand2.m_close) // 同事の始値が1番目のローソク足の終値以上
      pattern=DOJI_STAR_BEAR;
//--- 切り込み線(切り返し線)(強気)
   else if(cand1.m_trend==DOWN && cand1.m_bull && !cand2.m_bull && // トレンドとローソク足の方向の確認
      (cand1.m_type==CAND_LONG || cand1.m_type==CAND_MARIBOZU) && (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // 「ロング」ローソク足の確認
      cand1.m_close>(cand2.m_close+cand2.m_open)/2 && // 2番目のローソク足の終値が1番目のローソク足の中心点を上回る
      cand2.m_open>cand1.m_close && cand2.m_close>=cand1.m_open)
      pattern=PIERCING_LINE;
//--- かぶせ線(弱気)
   else if(cand1.m_trend==UPPER && !cand1.m_bull && cand2.m_bull && // トレンドとローソク足の方向の確認
      (cand1.m_type==CAND_LONG || cand1.m_type==CAND_MARIBOZU) && (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // 「ロング」ローソク足の確認
      cand1.m_close<(cand2.m_close+cand2.m_open)/2 && // 2番目のローソク足の終値が1番目のローソク足実体の中心点を下回る
      cand1.m_close<cand2.m_open && cand2.m_close<=cand1.m_open)
      pattern=DARK_CLOUD_COVER;
   return(pattern);
  }
//+------------------------------------------------------------------+

次のタイプのPatternTypeメソッドは、パターンタイプ引数の代わりに検索パターンの配列が渡されるという点で、前のメソッドとは異なります。

//+------------------------------------------------------------------+
//| パターン配列の認識                                                 |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN &pattern[],int shift)
  {
   for(int i=0;i<ArraySize(pattern);i++)
     {
      if(CheckPattern(symbol,timeframe,shift)==pattern[i])
         return(true);
     }
   return(false);
  }

次に、単純なタイプのローソク足から生成されたパターンを処理するためのPatternTypeメソッドの実装を考えてみましょう。これには、1、2、または3本のローソク足のパターンが含まれます。1つずつ見ていきましょう。

//+------------------------------------------------------------------+
//| ローソク足インデックスによるパターン認識                              |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,int shift)
  {
//--- ローソク足インデックスを検証する
   if(index<0 || index>11)
      return(false);
//---
   CANDLE_STRUCTURE cand,cur_cand;
   RATING_SET ratings;
   ZeroMemory(cand);
   IndexToPatternType(cand,index);
//--- 現在のローソク足タイプを取得する
   GetCandleType(symbol,timeframe,cur_cand,shift);                                // 現在のローソク足
//---
   if(cur_cand.m_type==cand.m_type && cur_cand.m_bull==cand.m_bull)
      return(true);
   return(false);
  }

これは1つのローソク足パターンを検索するメソッドの実装で、CandleType()メソッドと非常によく似ていますが、渡される引数の型と範囲は異なります。初めて使用されるプライベートメソッドIndextoPatternType()にご注意ください。

   //--- ローソク足インデックをタイプに変換する
   void              IndexToPatternType(CANDLE_STRUCTURE &res,int index);

単純な型のローソク足のインデックスをその型に変換し、指定された構造体に渡します。

以下は2本のローソク足から構成されるパターンのためのメソッドです。

//+------------------------------------------------------------------+
//| ローソク足インデックスによるパターン認識                              |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int shift)
  {
//--- ローソク足インデックスを検証する
   if(index1<0 || index1>11 || index2<0 || index2>11)
      return(false);
//---
   CANDLE_STRUCTURE cand1,cand2,cand3,cur_cand,prev_cand;
   RATING_SET ratings;
   ZeroMemory(cand1);
   ZeroMemory(cand2);
   IndexToPatternType(cand1,index1);
   IndexToPatternType(cand2,index2);
//--- 現在のローソク足タイプを取得する
   GetCandleType(symbol,timeframe,prev_cand,shift+1);                             // 1つ前のローソク足
   GetCandleType(symbol,timeframe,cur_cand,shift);                                // 現在のローソク足
//---
   if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && 
      prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull)
      return(true);
   return(false);
  }

コードの実装は前のものと非常によく似ています。ただし、分析にローソク足インデックスを選択するときは、パターンが2本のローソク足で構成されているためにローソク足タイプ「index1」は「shift」、「index2」は「shift+1」でシフトされるという特徴を考慮に入れる必要があります。同じ特徴は、3本のローソク足から構成されるパターンのためのメソッドの実装にも関係します。

//+------------------------------------------------------------------+
//| ローソク足インデックスによるパターン認識                              |
//+------------------------------------------------------------------+
bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,int shift)
  {
   CANDLE_STRUCTURE cand1,cand2,cand3,cur_cand,prev_cand,prev_cand2;
   RATING_SET ratings;
//---
   ZeroMemory(cand1);
   ZeroMemory(cand2);
   ZeroMemory(cand3);
//---
   IndexToPatternType(cand1,index1);
   IndexToPatternType(cand2,index2);
   IndexToPatternType(cand3,index3);

//--- 現在のローソク足タイプを取得する
   GetCandleType(symbol,timeframe,prev_cand2,shift+2);                            // 1つ前のローソク足
   GetCandleType(symbol,timeframe,prev_cand,shift+1);                             // 1つ前のローソク足
   GetCandleType(symbol,timeframe,cur_cand,shift);                                // 現在のローソク足
//---
   if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && 
      prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull && 
      prev_cand2.m_type==cand3.m_type && prev_cand2.m_bull==cand3.m_bull)
      return(true);
   return(false);
  }

Found

指定されたタイプの見つかったパターンの数を返します。既存のパターンTYPE_PATTERN、および1〜3本の単純なローソク足タイプで構成される生成パターンに対して、3つのメソッドオーバーロードがあります。

   //--- 指定されたタイプの見つかったパターンの数を返す
   int               Found(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern);
   int               Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index);
   int               Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2);
   int               Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3);

パラメータ

  • symbol  検索に選択された銘柄
  • timeframe  選択された時間枠
  • patternTYPE_PATTERNからの既存パターン
  • index,index1,index2,index3 単純な型のローソク足のインデックス(図1のブロック4)

戻り値

指定されたタイプで見つかったパターンの数

実装

メソッドの実装は非常に単純です。統計の収集に関連する主な操作は、プライベートメソッドPatternStat()によって実行されます。

//+------------------------------------------------------------------+
//| 指定されたタイプの見つかったパターンの数を返す                         |
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern)
  {
   PatternStat(symbol,timeframe,pattern);
   return(m_found);
  }
//+------------------------------------------------------------------+
//| 指定されたタイプの見つかったパターンの数を返す                         |
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1)
  {
   PatternStat(symbol,timeframe,index1);
   return(m_found);
  }
//+------------------------------------------------------------------+
//| 指定されたタイプの見つかったパターンの数を返す                         |
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2)
  {
   PatternStat(symbol,timeframe,index1,index2);
   return(m_found);
  }
//+------------------------------------------------------------------+
//| 指定されたタイプの見つかったパターンの数を返す                         |
//+------------------------------------------------------------------+
int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3)
  {
   PatternStat(symbol,timeframe,index1,index2,index3);
   return(m_found);
  }

PatternStat()メソッドには、既存パターンのためのものと生成されたパターンのためのものの2種類があります。もっと詳しく見てみましょう。最初のものは、TYPE_PATTERN列挙からの既存パターンのためのものです。

//+------------------------------------------------------------------+
//| 与えられたパターンに関する統計を取得する                              |
//+------------------------------------------------------------------+
CPattern::PatternStat(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern)
  {
//---
   int pattern_counter=0;
//---
   RATING_SET pattern_coef={0,0,0,0,0,0};
//---
   for(int i=m_range_total;i>4;i--)
     {
      if(CheckPattern(symbol,timeframe,i)==pattern)
        {
         pattern_counter++;
         if(pattern==HUMMER || pattern==INVERT_HUMMER || pattern==HANDING_MAN)
            GetCategory(symbol,timeframe,pattern_coef,i-3);
         else
            GetCategory(symbol,timeframe,pattern_coef,i-4);
        }
     }
//---
   CoefCalculation(pattern_coef,pattern_counter);
  }

2番目のものは、単純なローソク足タイプのインデックスからなる生成パターンに使用されます。

//+------------------------------------------------------------------+
//| 与えられたパターンに関する統計を取得する                              |
//+------------------------------------------------------------------+
void CPattern::PatternStat(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2=0,int index3=0)
  {
   CANDLE_STRUCTURE cand1,cand2,cand3,cur_cand,prev_cand,prev_cand2;
   RATING_SET rating={0,0,0,0,0,0};
   int pattern_total=0,pattern_size=1;
//---
   ZeroMemory(cand1);
   ZeroMemory(cand2);
   ZeroMemory(cand3);
   ZeroMemory(cur_cand);
   ZeroMemory(prev_cand);
   ZeroMemory(prev_cand2);
//---
   if(index2>0)
      pattern_size=2;
   if(index3>0)
      pattern_size=3;
//---
   if(pattern_size==1)
      IndexToPatternType(cand1,index1);
   else if(pattern_size==2)
     {
      IndexToPatternType(cand1,index1);
      IndexToPatternType(cand2,index2);
     }
   else if(pattern_size==3)
     {
      IndexToPatternType(cand1,index1);
      IndexToPatternType(cand2,index2);
      IndexToPatternType(cand3,index3);
     }
//---
   for(int i=m_range_total;i>5;i--)
     {
      if(pattern_size==1)
        {
         //--- 現在のローソク足タイプを取得する
         GetCandleType(symbol,timeframe,cur_cand,i);                                       // 現在のローソク足
         //---
         if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull)
           {
            pattern_total++;
            GetCategory(symbol,timeframe,rating,i-3);
           }
        }
      else if(pattern_size==2)
        {
         //--- 現在のローソク足タイプを取得する
         GetCandleType(symbol,timeframe,prev_cand,i);                                        // 1つ前のローソク足
         GetCandleType(symbol,timeframe,cur_cand,i-1);                                       // 現在のローソク足
         //---

         if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && 
            prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull)
           {
            pattern_total++;
            GetCategory(symbol,timeframe,rating,i-4);
           }
        }
      else if(pattern_size==3)
        {
         //--- 現在のローソク足タイプを取得する
         GetCandleType(symbol,timeframe,prev_cand2,i);                                       // 1つ前のローソク足
         GetCandleType(symbol,timeframe,prev_cand,i-1);                                      // 1つ前のローソク足
         GetCandleType(symbol,timeframe,cur_cand,i-2);                                       // 現在のローソク足
         //---
         if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && 
            prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull && 
            prev_cand2.m_type==cand3.m_type && prev_cand2.m_bull==cand3.m_bull)
           {
            pattern_total++;
            GetCategory(symbol,timeframe,rating,i-5);
           }
        }
     }
//---
   CoefCalculation(rating,pattern_total);
  }

これら2つのメソッド実装には1つの新しいメソッドが含まれています。これがプライベートメソッドCoefCalculation()です。

   //--- 係数を計算する        
   bool              CoefCalculation(RATING_SET &rate,int found);

パターンを検索およびテストしたときに得られたすべての結果を処理します。その引数には、パターン効率テストの結果と見つかったパターンの数に関するデータの収集を担当するRATING_SET構造体へのポインタが含まれています。解析されたパターンの他のすべてのパラメータとプロパティは、CoefCalculation()メソッドで計算されます。

//+------------------------------------------------------------------+
//| 効率評価係数の計算                                                 |
//+------------------------------------------------------------------+
bool CPattern::CoefCalculation(RATING_SET &rate,int found)
  {
   int sum1=0,sum2=0;
   sum1=rate.m_a_uptrend+rate.m_b_uptrend+rate.m_c_uptrend;
   sum2=rate.m_a_dntrend+rate.m_b_dntrend+rate.m_c_dntrend;
//---
   m_probability1=(found>0)?NormalizeDouble((double)sum1/found*100,2):0;
   m_probability2=(found>0)?NormalizeDouble((double)sum2/found*100,2):0;
   m_efficiency1=(found>0)?NormalizeDouble((m_k1*rate.m_a_uptrend+m_k2*rate.m_b_uptrend+m_k3*rate.m_c_uptrend)/found,3):0;
   m_efficiency2=(found>0)?NormalizeDouble((m_k1*rate.m_a_dntrend+m_k2*rate.m_b_dntrend+m_k3*rate.m_c_dntrend)/found,3):0;
   m_found=found;
   m_coincidence=((double)found/m_range_total*100);
   return(true);
  }

Coincidence

パターン発生頻度を返します。既存のパターンTYPE_PATTERN、および1〜3本の単純なローソク足タイプで構成される生成パターンに対して、3つのメソッドオーバーロードがあります。

   //--- パターン発生頻度を返す
   double            Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern);
   double            Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index);
   double            Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2);
   double            Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3);

パラメータ

  • symbol検索に選択された銘柄
  • timeframe選択された時間枠
  • patternTYPE_PATTERNからの既存パターン
  • index,index1,index2,index3単純な型のローソク足のインデックス(図1のブロック4)

戻り値

パターン発生の頻度(パーセント)

実装

Found()メソッドと似ています。唯一の違いはm_coincidence変数値が返されることです。

//+------------------------------------------------------------------+
//| パターン発生頻度を返す                                              |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern)
  {
   PatternStat(symbol,timeframe,pattern);
   return(m_coincidence);
  }
//+------------------------------------------------------------------+
//| パターン発生頻度を返す                                              |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1)
  {
   PatternStat(symbol,timeframe,index1);
   return(m_coincidence);
  }
//+------------------------------------------------------------------+
//| パターン発生頻度を返す                                              |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2)
  {
   PatternStat(symbol,timeframe,index1,index2);
   return(m_coincidence);
  }
//+------------------------------------------------------------------+
//| パターン発生頻度を返す                                              |
//+------------------------------------------------------------------+
double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3)
  {
   PatternStat(symbol,timeframe,index1,index2,index3);
   return(m_coincidence);
  }

Probability

指定されたパターン発生後の移動確率を返します。既存のパターンTYPE_PATTERN、および1〜3本の単純なローソク足タイプで構成される生成パターンに対して、3つのメソッドオーバーロードがあります。

   //--- 指定されたパターン発生後の移動確率を返す 
   double            Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend);
   double            Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,TYPE_TREND trend);
   double            Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend);
   double            Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend);

パラメータ

  • symbol検索に選択された銘柄
  • timeframe選択された時間枠
  • patternTYPE_PATTERNからの既存パターン
  • index、index1、index2、index 3単純な型のローソク足のインデックス(図1のブロック4)

  • trendTYPE_TREND
//+------------------------------------------------------------------+
//| トレンドタイプ                                                     |
//+------------------------------------------------------------------+
enum TYPE_TREND
  {
   UPPER,               // 上昇
   DOWN,                // 下降
   FLAT                 // フラット
  };
//+------------------------------------------------------------------+

戻り値

指定されたパターン発生後の移動確率

実装

Found()メソッドと似ています。唯一の違いは、トレンドの種類によって、m_probability1またはm_probability2変数値が返されることです。

//+------------------------------------------------------------------+
//| 指定されたパターン発生後の移動確率を返す                              |
//+------------------------------------------------------------------+
double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,pattern);
   if(trend==UPPER)
      return(m_probability1);
   if(trend==DOWN)
      return(m_probability2);
   return(0);
  }
//+------------------------------------------------------------------+
//| 指定されたパターン発生後の移動確率を返す                              |
//+------------------------------------------------------------------+
double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1);
   if(trend==UPPER)
      return(m_probability1);
   if(trend==DOWN)
      return(m_probability2);
   return(0);
  }
//+------------------------------------------------------------------+
//| 指定されたパターン発生後の移動確率を返す                              |
//+------------------------------------------------------------------+
double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1,index2);
   if(trend==UPPER)
      return(m_probability1);
   if(trend==DOWN)
      return(m_probability2);
   return(0);
  }
//+------------------------------------------------------------------+
//| 指定されたパターン発生後の移動確率を返す                              |
//+------------------------------------------------------------------+
double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1,index2,index3);
   if(trend==UPPER)
      return(m_probability1);
   if(trend==DOWN)
      return(m_probability2);
   return(0);
  }

Efficiency

パターン効率係数を返します。既存のパターンTYPE_PATTERN、および1〜3本の単純なローソク足タイプで構成される生成パターンに対して、3つのメソッドオーバーロードがあります。

   //--- パターン効率係数を返す 
   double            Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend);
   double            Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,TYPE_TREND trend);
   double            Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend);
   double            Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend);

パラメータ

  • symbol検索に選択された銘柄
  • timeframe選択された時間枠
  • patternTYPE_PATTERNからの既存パターン
  • index,index1,index2,index3単純な型のローソク足のインデックス(図1のブロック4)
  • trendトレンドタイプ、TYPE_TREND
//+------------------------------------------------------------------+
//| トレンドタイプ                                                     |
//+------------------------------------------------------------------+
enum TYPE_TREND
  {
   UPPER,               // 上昇
   DOWN,                // 下降
   FLAT                 // フラット
  };
//+------------------------------------------------------------------+

戻り値

パターン効率係数

実装

Found()メソッドと似ています。唯一の違いは、トレンドの種類によって、m_coincidence1またはm_efficiency2変数値が返されることです。

//+------------------------------------------------------------------+
//| 指定されたパターン発生後の移動確率を返す                              |
//+------------------------------------------------------------------+
double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,pattern);
   if(trend==UPPER)
      return(m_efficiency1);
   if(trend==DOWN)
      return(m_efficiency2);
   return(0);
  }
//+------------------------------------------------------------------+
//| 指定されたパターン発生後の移動確率を返す                              |
//+------------------------------------------------------------------+
double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1);
   if(trend==UPPER)
      return(m_efficiency1);
   if(trend==DOWN)
      return(m_efficiency2);
   return(0);
  }
//+------------------------------------------------------------------+
//| 指定されたパターン発生後の移動確率を返す                              |
//+------------------------------------------------------------------+
double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1,index2);
   if(trend==UPPER)
      return(m_efficiency1);
   if(trend==DOWN)
      return(m_efficiency2);
   return(0);
  }
//+------------------------------------------------------------------+
//| 指定されたパターン発生後の移動確率を返す                              |
//+------------------------------------------------------------------+
double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend)
  {
   PatternStat(symbol,timeframe,index1,index2,index3);
   if(trend==UPPER)
      return(m_efficiency1);
   if(trend==DOWN)
      return(m_efficiency2);
   return(0);
  }

実用的な使い方

パターンを扱うためのツールを検討したので、ライブラリの使用例を示すために2つの指標とエキスパートアドバイザーを実装しましょう。

CandleDetector

TYPE_CANDLESTICK列挙型から選択されたタイプのローソク足をチャートに表示する指標から始めます。IndicatorsフォルダにPatternフォルダを作成します。このフォルダに、指標を含むことになるCandleDetector.mq5ファイルを作成します。Pattern.mqhライブラリをパターン操作のためにリンクし、指標の初期プロパティを設定しましょう。

//+------------------------------------------------------------------+
//|                                               CandleDetector.mq5 |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                           https://www.mql5.com/ja/users/alex2356 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com/ja/users/alex2356"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
#include <Pattern/Pattern.mqh>
//+----------------------------------------------+
//|  指標描画パラメータ                            |
//+----------------------------------------------+
//---- ラベルとして指標を描画
#property indicator_type1   DRAW_ARROW
//---- 指標の線の太さ
#property indicator_width1  1

次のステップは、これまたはそのローソク足タイプの表示に影響するキー設定を決定することです。 

//+----------------------------------------------+
//| 指標入力パラメータ                             |
//+----------------------------------------------+
input TYPE_CANDLESTICK  CandleType=1;                 // ローソク足タイプ
input color             LabelColor=clrCrimson;
input double            LongCoef=1.3;
input double            ShortCoef=0.5;
input double            DojiCoef=0.04;
input double            MaribozuCoef=0.01;
input double            SpinCoef=1;
input double            HummerCoef1=0.1;
input double            HummerCoef2=2;
input int               TrendPeriod=5; 

次に、初期化で、指標の外観を設定し、検索用の入力パラメータからすべての値を決定します。

//+------------------------------------------------------------------+
//| カスタム指標初期化関数                                              |
//+------------------------------------------------------------------+
int OnInit()
  {
//---- データ計算変数の初期化を開始
   min_rates_total=TrendPeriod+1;
//---- 表示される指標値の精度を定義する
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);

//---- Signal[]動的配列を指標バッファとして設定する
   SetIndexBuffer(0,Signal,INDICATOR_DATA);
//---- シフト指標1の描画を開始
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,min_rates_total);
//---- バッファ内の要素のインデックス付けを時系列同様に設定する   
   ArraySetAsSeries(Signal,true);
//---- チャートに表示されない指標値を設定する
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//---- 指標シンボル
   PlotIndexSetInteger(0,PLOT_ARROW,108);
//---
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,LabelColor);
//----
   Pat.Long_coef(LongCoef);
   Pat.Short_coef(ShortCoef);
   Pat.Doji_coef(DojiCoef);
   Pat.Maribozu_coef(MaribozuCoef);
   Pat.Spin_coef(SpinCoef);
   Pat.Hummer_coef1(HummerCoef1);
   Pat.Hummer_coef2(HummerCoef2);
   Pat.TrendPeriod(TrendPeriod);
   return(INIT_SUCCEEDED);
  }

CandleType()メソッドにご注意ください。このメソッドは、チャートで選択されたローソク足タイプを探すのに使用されます。

//+------------------------------------------------------------------+
//| カスタム指標反復関数                                               |
//+------------------------------------------------------------------+
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<min_rates_total)
      return(0);
//---- ローカル変数を宣言する 
   int limit,bar;
//---- 配列要素のインデックス付けを時系列同様に設定する  
   ArraySetAsSeries(low,true);
//---- バーの再計算ループの「最初の」開始番号を計算する
   if(prev_calculated>rates_total || prev_calculated<=0)          // 指標計算の初めの開始点を確認する
      limit=rates_total-min_rates_total;                          // すべてのバーを計算するための開始インデックス
   else
      limit=rates_total-prev_calculated;                          // 新しいバーを計算するための開始インデックス
//---- 指標計算のメインループ
   for(bar=limit; bar>=0; bar--)
     {
      Signal[bar]=0.0;
      if(Pat.CandleType(Symbol(),PERIOD_CURRENT,bar)==CandleType)
         Signal[bar]=low[bar]-200*_Point;
     }
   return(rates_total);
  }
//+------------------------------------------------------------------+

図3に指標操作例(「Long」型ローソク足の検索)を示します。

図3 CandleDetector指標の操作例

PatternDetector

2番目の指標は、TYPE_PATTERN列挙体から指定されたパターンを検索します。実装は前のものと非常によく似ています。違いは入力パラメータ計算メソッドです。

//+----------------------------------------------+
//| 指標入力パラメータ                             |
//+----------------------------------------------+
input TYPE_PATTERN      PatternType=1;                // パターンタイプ
input color             LabelColor=clrCrimson;
input double            LongCoef=1.3;
input double            ShortCoef=0.5;
input double            DojiCoef=0.04;
input double            MaribozuCoef=0.01;
input double            SpinCoef=1;
input double            HummerCoef1=0.1;
input double            HummerCoef2=2;
input int               TrendPeriod=5;
//---
CPattern Pat;
double Signal[];
//---- データ計算開始の整数変数を宣言する
int min_rates_total;
//+------------------------------------------------------------------+
//| カスタム指標初期化関数                                              |
//+------------------------------------------------------------------+  
void OnInit()
  {
//---- データ計算変数の初期化を開始
   min_rates_total=TrendPeriod+2;
//---- 表示される指標値の精度を定義する
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);

//---- SignUp[]動的配列を指標バッファとして設定する
   SetIndexBuffer(0,Signal,INDICATOR_DATA);
//---- シフト指標1の描画を開始
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,min_rates_total);
//---- バッファ内の要素のインデックス付けを時系列同様に設定する   
   ArraySetAsSeries(Signal,true);
//---- チャートに表示されない指標値を設定する
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
//---- 指標シンボル
   PlotIndexSetInteger(0,PLOT_ARROW,108);
//---
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,LabelColor);
//----
   Pat.Long_coef(LongCoef);
   Pat.Short_coef(ShortCoef);
   Pat.Doji_coef(DojiCoef);
   Pat.Maribozu_coef(MaribozuCoef);
   Pat.Spin_coef(SpinCoef);
   Pat.Hummer_coef1(HummerCoef1);
   Pat.Hummer_coef2(HummerCoef2);
   Pat.TrendPeriod(TrendPeriod);
  }
//+------------------------------------------------------------------+
//| カスタム指標反復関数                                               |
//+------------------------------------------------------------------+
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<min_rates_total)
      return(0);
//---- ローカル変数を宣言する 
   int limit,bar;
//---- 配列要素のインデックス付けを時系列同様に設定する  
   ArraySetAsSeries(low,true);
//---- バーの再計算ループの「最初の」開始番号を計算する
   if(prev_calculated>rates_total || prev_calculated<=0)       // 指標計算の初めの開始点を確認する
      limit=rates_total-min_rates_total;                       // すべてのバーを計算するための開始インデックス
   else
      limit=rates_total-prev_calculated;                       // 新しいバーを計算するための開始インデックス
//---- 指標計算のメインループ
   for(bar=limit; bar>0; bar--)
     {
      Signal[bar]=0.0;
      if(Pat.PatternType(_Symbol,_Period,PatternType,bar))
         Signal[bar]=low[bar]-200*_Point;
     }
   return(rates_total);
  }
//+------------------------------------------------------------------+

図4にPatternDetectorの操作(Engulfing - 強気パターンの検索)の結果を示します。

図4 PatternDetector指標の操作例

ここで、チャート上のパターンを見つけ、選択したパターンに応じてポジションをオープンできるエキスパートアドバイザーを作成しましょう。各取引タイプには、個別のパターンタイプを使用できます。追加モードでは、既存のパターンと単純なローソク足タイプを使用して生成されたパターンの間の選択が可能になります。

ExpertsフォルダにPatternフォルダを作成し、PatternExpert.mq5を追加します。EAコードはこのファイルに書き込まれます。最初の段階で、パターンを処理するためのPattern.mqhライブラリとTrade.mqh取引操作ライブラリを結びつけます。クラスインスタンスを宣言し、既存のパターンと生成されたパターンを切り替えることを可能にするPATTERN_MODE列挙を導入します。

//+------------------------------------------------------------------+
//|                                                PatternExpert.mq5 |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                           https://www.mql5.com/ja/users/alex2356 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://www.mql5.com/ja/users/alex2356"
#property version   "1.00"
#include <Pattern/Pattern.mqh>
#include "Trade.mqh" 
CTradeBase Trade;
CPattern Pat;
//+------------------------------------------------------------------+
//| パターン検索モード                                                 |
//+------------------------------------------------------------------+
enum PATTERN_MODE
  {
   EXISTING,
   GENERATED
  };

エキスパートアドバイザーの入力パラメータを定義します。EAパラメータは1番目のブロックにあります。

//+------------------------------------------------------------------+
//| エキスパートアドバイザーの入力パラメータ                              |
//+------------------------------------------------------------------+
input    string               Inp_EaComment="Pattern Strategy";         // EAコメント
input    double               Inp_Lot=0.01;                             // ロット
input    MarginMode           Inp_MMode=LOT;                            // 資金管理

//--- EAパラメータ
input    string               Inp_Str_label="===EA parameters===";      // ラベル
input    int                  Inp_MagicNum=1111;                        // マジックナンバー
input    int                  Inp_StopLoss=40;                          // ストップロス(ポイント単位)
input    int                  Inp_TakeProfit=30;                        // テイクプロフィット(ポイント単位)

2番目の部分には、設定と取引パラメータが含まれています。 

//--- 取引パラメータ
input ENUM_TIMEFRAMES         Timeframe=PERIOD_CURRENT;                 // 現在の時間枠
input PATTERN_MODE            PatternMode=0;                            // パターンモード
input TYPE_PATTERN            BuyPatternType=ENGULFING_BULL;            // 買いパターンタイプ
input TYPE_PATTERN            SellPatternType=ENGULFING_BEAR;           // 売りパターンタイプ
input uint                    BuyIndex1=1;                              // 単純candle1の買いインデックス
input uint                    BuyIndex2=0;                              // 単純candle2の買いインデックス
input uint                    BuyIndex3=0;                              // 単純candle3の買いインデックス
input uint                    SellIndex1=1;                             // 単純candle1の売りインデックス
input uint                    SellIndex2=0;                             // 単純candle2の売りインデックス
input uint                    SellIndex3=0;                             // 単純candle3の売りインデックス
input double                  LongCoef=1.3;                             // ロングローソク足係数
input double                  ShortCoef=0.5;                            // ショートローソク足係数
input double                  DojiCoef=0.04;                            // 同事ローソク足係数
input double                  MaribozuCoef=0.01;                        // 丸坊主ローソク足係数
input double                  SpinCoef=1;                               // コマ(極線)ローソク足係数
input double                  HummerCoef1=0.1;                          // 唐笠ローソク足係数1
input double                  HummerCoef2=2;                            // 唐笠ローソク足係数2
input int                     TrendPeriod=5;                            // トレンド期間

これらのパラメータのいくつかをさらに詳しく検討しましょう。

  • Current Timeframe — 操作のために選択された時間枠。最適化に時間枠を選択できます。デフォルトでは現在のチャートの時間枠が選択されています。
  • Pattern Mode — パターン選択モードEXISTING — 既存パターン: このモードでは、買いパターンタイプと売りパターンタイプの2つの設定が適用されます。 GENERATED - 生成されたパターン: このモードでは、買/売パターンタイプの設定は無視され、代わりにBuyIndex1~3およびSellIndex1~3が使用されます。
  • Buy Pattern Type/ Sell Pattern Type — 適切な取引操作を開始するためのパターンを選択 
  • BuyIndex1-3/SellIndex1-3 — 単純タイプのローソク足で生成されたパターンを選択し(図1ブロック4)、出現するとロング/ショートポジションが開かれます。 

他のパラメーターは上記の考慮された指標と類似しています。確認に加えて、初期化ブロックではトレンド期間値が設定されます。これはチャート上のパターン検出に影響します。

//+------------------------------------------------------------------+
//| エキスパート初期化関数                                              |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- 取引サーバへの接続の確認
   if(!TerminalInfoInteger(TERMINAL_CONNECTED))
     {
      Print(Inp_EaComment,": No Connection!");
      return(INIT_FAILED);
     }
//--- 自動取引権限の確認
   if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
     {
      Print(Inp_EaComment,": Trade is not allowed!");
      return(INIT_FAILED);
     }
//---
   Pat.TrendPeriod(TrendPeriod);
//---
   return(INIT_SUCCEEDED);
  }

計算の部分は簡単に理解できます。売買シグナル検索関数を見てみましょう。

//+------------------------------------------------------------------+
//| エキスパートティック関数                                            |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(!Trade.IsOpenedByMagic(Inp_MagicNum))
     {
      //--- 買いシグナルがある場合の発注
      if(BuySignal())
         Trade.BuyPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss,Inp_TakeProfit,Inp_MagicNum,Inp_EaComment);
      //--- 売りシグナルがある場合の発注
      if(SellSignal())
         Trade.SellPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss,Inp_TakeProfit,Inp_MagicNum,Inp_EaComment);
     }
  }

これらの関数は似ているので、買いシグナルを検索するBuySignal()のみを考察します。

//+------------------------------------------------------------------+
//| 買いの条件                                                        |
//+------------------------------------------------------------------+
bool BuySignal()
  {
   if(PatternMode==0)
     {
      if(BuyPatternType==NONE)
         return(false);
      if(Pat.PatternType(_Symbol,Timeframe,BuyPatternType,1))
         return(true);
     }
   else if(PatternMode==1)
     {
      if(BuyIndex1>0 && BuyIndex2==0 && BuyIndex3==0)
        {
         if(Pat.PatternType(_Symbol,Timeframe,BuyIndex1,1))
            return(true);
        }
      else if(BuyIndex1>0 && BuyIndex2>0 && BuyIndex3==0)
        {
         if(Pat.PatternType(_Symbol,Timeframe,BuyIndex1,BuyIndex2,1))
            return(true);
        }
      else if(BuyIndex1>0 && BuyIndex2>0 && BuyIndex3>0)
        {
         if(Pat.PatternType(_Symbol,Timeframe,BuyIndex1,BuyIndex2,BuyIndex3,1))
            return(true);
        }
     }
   return(false);
  }

この関数には、現在選択されているモード(既存のパターンまたは生成されたパターン)の確認が含まれています。入力パラメータはそれに応じてTYPE_PATTERNまたは生成されたパターンのインデックスのセットから選択されます。

TYPE_PATTERN列挙体からの既存のパターンと、図1ブロック4に示す単純タイプのローソク足からなる生成パターンを使用して、2つのモードで、エキスパートアドバイザーをテストおよび最適化しましょう。

テストには以下のパラメータを使用します。

  • Interval: 上昇トレンドモード(01.01.2018 — 15.03.2018)
  • Currency pair: EURUSD
  • Trading mode: 遅延なし。これらは高頻度の取引戦略ではないため、遅延の影響はごくわずかです。
  • Testing: 1分OHLC 
  • Initial deposit: 1000 USD
  • Leverage: 1:500
  • Server: MetaQuotes-Demo
  • Quotes: 5桁

[生成されたパターン]モード

テストし最適化するパラメータを特定します。

図5 [生成されたパターン]モードでの最適化対象のパラメータセット

図5にテストと最適化の条件を示します。テストの結果として得られた最良のパラメータは、2列目の[値]に示されています。以下の図6にバックテストの結果とチャートを示します。 

図6 [生成されたパターン]モードでの最良のパラメーターテスト結果

[既存パターン]モード。

テストと最適化のためのパラメータを設定します。

図7 [既存パターン]モードでの最適化対象のパラメータセット 

最善の最適化結果のパラメータは再度2列目に表示されています。ここで、単一のテストを実行します。結果は以下の図8に示します。

図8 [既存パターン]モードでの最良のパラメーターテスト結果


終わりに

以下の添付ファイルには、説明されたすべてのファイルがフォルダに正しく分類されています。正しい操作のためには、MQL5フォルダを端末のルートフォルダに保存してください。MQL5フォルダがあるこのルートフォルダを見つけるには、MetaTrader 5でCtrl+Shift+Dを押すか、図9に示すようにコンテキストメニューを使用してください。

図9 MetaTrader5ルートディレクトリでMQL5フォルダを見つける方法

記事で使用されているプログラム

#
 名称
種類
説明
1
Pattern.mqh ライブラリ  パターン操作ライブラリ
2 CandleDetector.mq5 指標  ローソク足検索指標
3 PatternDetector.mq5 指標  パターン検索指標
4 PatternExpert.mq5  エキスパートアドバイザー   パターン操作取引エキスパートアドバイザー
5 Trade.mqh ライブラリ  取引関数のクラス