ローソク足分析技術の研究(第3部): パターン操作のライブラリ
Alexander Fedosov | 18 7月, 2019
目次
- はじめに
- ライブラリの構造
- ライブラリの開発
- CandleType - 選択されたローソク足タイプ
- PatternType - パターンタイプ
- Found - 指定されたタイプで見つかったパターンの数
- Coincidence - 指定されたパターンタイプが見つかる頻度
- Probability - パターン発生後の移動確率
- Efficiency - パターン効率係数
- 実用的な使い方
- 終わりに
はじめに
ローソク足分析の手法についてはすでに検討しました。現在の市場状況下でのパターンの実際性は第1部で確認され、これらの研究を拡大する試みは第2部で行われました。開発評価基準を用いて、広範囲の可能なパターンの組み合わせが研究され、テストされ、比較されました。この目的のために、パターンを研究するための多数の設定を備えたカスタムパターンアナライザアプリケーションが開発されました。しかしながら、理論と研究は情報と結論を提供することしかできません。タスクの論理的な継続は、実際の状況での使用です。
本稿の目的は、カスタムツールを作成して、前述のパターンに関する一連の情報全体を受信して使用できるようにすることです。ユーザが独自の指標、取引パネル、エキスパートアドバイザーなどで使用できるライブラリが作成されます。
ライブラリの構造
ライブラリ構造、クラス、接続の作成に進む前に、使用するデータを定義しましょう。つまり、入力データを担当するメソッドと結果を提供するメソッドを分離する必要があります。一般的なライブラリ構造は、以前の記事で開発されたビジュアルソリューションであるパターンアナライザに基づいています。
パターンをテストするときに結果に影響を与える可能性があるアプリケーション入力データから始めましょう。
図1 [設定]タブの入力パラメータ
ブロック1 既存のパターンと生成されたパターンを構成するローソク足のタイプのリストを特徴としています。それぞれのタイプには設定があり、ローソク足の視覚化ページの右上隅にある歯車のアイコンをクリックすると表示できます。ローソク足タイプ1〜5には1つの設定しかありませんが、「唐笠」には2つの設定があります。
ブロック2 重み係数。パターン効率評価結果に影響を与える3つのパラメータК1、К2、К3があります。
ブロック3 ポイント単位のトレンド閾値。
ブロック4 生成されたパターンのテストに使用されるローソク足。ここでは、シーケンス番号またはローソク足インデックスが必要になります。このデータを使用して、最大3つのローソク足まで、任意のサイズの任意のパターンに関する情報を取得できます。
ブロック5 パターンの中のローソク足数。この設定は、カスタムパターンにのみ適用されます。
[分析]タブとそこに含まれている入力パラメータを見てみましょう。
図2 [分析]タブの入力パラメータ
ブロック6 パターン解析に使用される現在の時間枠とデータサンプル範囲の設定が含まれています。
ブロック7 既存パターンの名前。パターンにアクセスしてそれに関する情報を取得するために必要であるがアプリケーションからは編集できない入力もあります。
ここでパターン分析から得られるデータを列挙しましょう。これは、クラス内でメソッドの正しい構造を作成するために必要です。
- Patterns found 指定されたタイプで見つかったパターンの数。
- Occurrenceサンプル範囲全体から見つかったパターン数の割合。
- 上向きまたは下向きの動きの確率。
- このローソク足パターンの上下移動中の効率比。
ライブラリの開発
基本的なポイントを決めたら、ライブラリの作成に進みましょう。必要な列挙体を持つファイル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 CandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,const int shift);
パラメータ
- symbol — 検索に選択された銘柄
- timeframe — 選択された時間枠
- 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);
パラメータ
- symbol — 検索に選択された銘柄
- timeframe — 選択された時間枠
- pattern,pattern[] — TYPE_PATTERNからの既存パターン。
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 };
- index,index1,index2,index3 — 単純な型のローソク足のインデックス(図1のブロック4)
- shift — 0から始まり、分析のために選択されたローソク足のインデックス
戻り値
ブール値
実装
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 — 選択された時間枠
- pattern — TYPE_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 — 選択された時間枠
- pattern — TYPE_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 — 選択された時間枠
- pattern — TYPE_PATTERNからの既存パターン
- index、index1、index2、index 3— 単純な型のローソク足のインデックス(図1のブロック4)
- trend— TYPE_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 — 選択された時間枠
- pattern — TYPE_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 | ライブラリ | 取引関数のクラス |