ローソク足分析技術の研究(第2部): 新規パターンの自動検索

Alexander Fedosov | 14 5月, 2019

目次

はじめに

前の記事では既存のローソク足分析方法が分析され、それらが普遍的ではなく、すべての条件に適しているわけではないことがわかりました。それどころか、これらを使用する前には、パターンが使用される特定の金融商品、時間枠などの条件について追加の検証を実行する必要があります。

特別に設計されたアプローチによって、選択された金融商品や商品セットについて各パターンの個々の分析ができます。また、時間枠やサンプル範囲、発生頻度、パターン形成後の特定の方向への移動の可能性などの特別に入力された測定基準を含む、定義済みパラメータ間の可能な相関関係を見つけることもできます。

分析方法は、多種多様な既存のローソク足形成から選択された14パターンのみを対象としています。すべてのパターンを1つずつ分析することは不可能であるため、別の解決策を見つけました。先に調べたすべてのパターンの重要な特徴はそれらの基礎、すなわちそれらが何からなるのかということでした。分析されたローソク足パターンのうちの4つは1つのローソク足、10は2つのローソク足から成るものでした。分析されたローソク足パターンは、6つのローソク足タイプの異なるセットまたはシーケンスで構成されていました。

一番の問題は、市場の特性、行動、およびダイナミクスが絶えず変化している一方、パターンは昔に登場したということです。市場分析の動向に合わせて、パターン分析にもいくつかの修正を加える必要があります。本稿では、既知のローソク足タイプに基づいて新しいローソク足パターンを検索およびテストするためのシステムについて考察します。 


タスクの特定

新しいローソク足パターン生成アルゴリズムを開発するためには、キーとなる規則を定義する必要があります。

新規パターン作成の一般的な仕組みを図1に示します。


図1 新規パターン作成アルゴリズム

ローソク足の一定のセットから新しいパターンが形成されることになります。これらの新しいパターンには、繰り返しの有無にかかわらず1〜3本のローソク足が含まれます。セットには全部で11の基本ローソク足が含まれます。生成されたローソク足パターンは、最初の記事で説明したのと同じ原則に従って分析されます。


インターフェイスプロトタイプの更新

生成されたパターンを操作するためには別のタブが利用可能になります。このタブには、既存のAnalyze(分析)タブと似た要素が含まれます。唯一の違いは、最初の列がSetという名前で、表のサイズが固定されていないことです。

図2 生成されたパターンを操作するためのタブ

3番目のSettings(設定)タブは大幅に修正されました。このタブではパラメータを正しく構成することが重要なため、このタブは詳細に検討します。

図3 更新された[Settings]タブ

  1. 基本ローソク足タイプとそれらの名前の番号付けを追加しました。したがって、視覚的表現を[Used candles](使用されるローソク足)リストと簡単に一致させることができます。
  2. インターフェイス言語を選択するためのオプションを追加しました (ロシア語または英語)。
  3. パターン形成に参加する[Used candles](使用されるローソク足)のリスト。 チェックボックスを使用すると、テストに必要な種類を選択できます。
  4. 切り替え可能なボタンのグループ。選択できるポジションは1つだけです。このようにして、[AutoSearch](自動検索)タブで生成されたパターンリストが多重定義されるのを避けます。
  5. 2つの切り替え可能なボタン。[Repeat](繰り返しあり)は、パターン内に1つのローソク足タイプしか存在できないことを意味します。 一例は、3つの弱気な丸坊主ローソク足からなるパターンです。 同時に、コマ(極線) - 丸坊主 - 丸坊主パターンも存在することができます。

ツールの実装

既存のアプリケーションに実装する必要がある主な追加事項が決定されたので、実装自体に進みましょう。まず第一に、追加のタブが必要です。タブのインデックスが変わります。[AutoSearch](自動検索)タブのインデックスは1になります。このインデックスは以前は[Settings](設定)タブで使用されていました。[Settings]には2が使用されます。これは、子要素をリンクするときに考慮する必要があります。したがって、[Settings]タブのすべての子要素のインデックスを1から2に変更する必要があります。

//+------------------------------------------------------------------+
//| タブのグループを作成する                                              |
//+------------------------------------------------------------------+
bool CProgram::CreateTabs(const int x_gap,const int y_gap)
  {
#define TABS1_TOTAL 3
//--- メインコントロールへのポインタを格納する
   m_tabs1.MainPointer(m_window1);
//--- プロパティ
   m_tabs1.IsCenterText(true);
   m_tabs1.PositionMode(TABS_TOP);
   m_tabs1.AutoXResizeMode(true);
   m_tabs1.AutoYResizeMode(true);
   m_tabs1.AutoXResizeRightOffset(3);
   m_tabs1.AutoYResizeBottomOffset(25);

//--- 指定されたプロパティを持つタブを追加する
   string tabs_names[TABS1_TOTAL]={"Analysis","Auto search","Settings"};
   for(int i=0; i<TABS1_TOTAL; i++)
      m_tabs1.AddTab(tabs_names[i],150);
//--- コントロールの作成
   if(!m_tabs1.CreateTabs(x_gap,y_gap))
      return(false);
//--- オブジェクトグループの共通配列にオブジェクトを追加する
   CWndContainer::AddToElementsArray(0,m_tabs1);
   return(true);
  }

[自動検索]タブの子要素は[分析]タブのものと似ています。唯一の違いは、最初の列の名前と配色です。これにより、これらのタブのインターフェイス要素を視覚的に区別することができます。

//+------------------------------------------------------------------+
//| コントロールのフォームを作成する                                      |
//+------------------------------------------------------------------+
bool CProgram::CreateWindow(const string caption_text)
  {
//--- ウィンドウ配列へのポインタを追加する
   CWndContainer::AddWindow(m_window1);
//--- プロパティ
   m_window1.XSize(750);
   m_window1.YSize(500);
   m_window1.FontSize(9);
   m_window1.IsMovable(true);
   m_window1.CloseButtonIsUsed(true);
   m_window1.CollapseButtonIsUsed(true);
   m_window1.FullscreenButtonIsUsed(true);
   m_window1.TooltipsButtonIsUsed(true);
//--- フォームの作成
   if(!m_window1.CreateWindow(m_chart_id,m_subwin,caption_text,5,5))
      return(false);
//--- タブ
   if(!CreateTabs(3,43))
      return(false);
//--- [Analysis]タブ
//--- フィールドを編集する
   if(!CreateSymbolsFilter(m_symb_filter1,10,10,"Symbols",0))
      return(false);
   if(!CreateRequest(m_request1,250,10,"Search",0))
      return(false);
   if(!CreateRange(m_range1,485,10,"Range",0))
      return(false);
//--- コンボボックス
   if(!CreateComboBoxTF(m_timeframes1,350,10,"Timeframe",0))
      return(false);
//--- 銘柄表の作成
   if(!CreateSymbTable(m_symb_table1,10,50,0))
      return(false);
//--- 結果表の作成
   if(!CreateTable1(m_table1,120,50,0))
      return(false);

//--- [AutoSearch]タブ
//--- フィールドを編集する
   if(!CreateSymbolsFilter(m_symb_filter2,10,10,"Symbols",1))
      return(false);
   if(!CreateRequest(m_request2,250,10,"Search",1))
      return(false);
   if(!CreateRange(m_range2,485,10,"Range",1))
      return(false);
//--- コンボボックス
   if(!CreateComboBoxTF(m_timeframes2,350,10,"Timeframe",1))
      return(false);
//--- 銘柄表の作成
   if(!CreateSymbTable(m_symb_table2,10,50,1))
      return(false);
//--- 結果表の作成
   if(!CreateTable2(m_table2,120,50,1))
      return(false);

上記のコードからわかるように、違いはCreateTable1()CreateTable2()の2つのメソッドにのみ関係します。それでは、[Settings]タブに進みましょう。ここで一番最初の変更はグラフィックリソースに関するものです。ローソク足のパラメータ設定要素も作成要素に追加されました。これはCreateNameCandle()メソッドを使って行われます。

//+------------------------------------------------------------------+
//| ローソク足設定要素を作成する                                            |
//+------------------------------------------------------------------+
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\settings_dark.bmp"
#resource "\\Images\\EasyAndFastGUI\\Candles\\long.bmp"
#resource "\\Images\\EasyAndFastGUI\\Candles\\short.bmp"
#resource "\\Images\\EasyAndFastGUI\\Candles\\doji.bmp"
#resource "\\Images\\EasyAndFastGUI\\Candles\\spin.bmp"
#resource "\\Images\\EasyAndFastGUI\\Candles\\maribozu.bmp"
#resource "\\Images\\EasyAndFastGUI\\Candles\\hammer.bmp"
//---
bool CProgram::CreateCandle(CPicture &pic,CButton &button,CTextLabel &candlelabel,const string candlename,const int x_gap,const int y_gap,string path)
  {
//--- メインコントロールへのポインタを格納する
   pic.MainPointer(m_tabs1);
//--- タブに取り付ける
   m_tabs1.AddToElementsArray(2,pic);
//--- プロパティ
   pic.XSize(64);
   pic.YSize(64);
   pic.IconFile(path);
//--- ボタンの作成
   if(!pic.CreatePicture(x_gap,y_gap))
      return(false);
//--- 要素へのポインタをベースに追加する
   CWndContainer::AddToElementsArray(0,pic);
   CreateButtonPic(pic,button,"Images\\EasyAndFastGUI\\Icons\\bmp16\\settings_dark.bmp");
   CreateNameCandle(candlelabel,x_gap,y_gap+pic.YSize(),candlename);
   return(true);
  }

これで、既に作成されているコントロールに関する変更点がすべてわかったので、新しいコントロールを見ていきましょう。そのうちの1つはインターフェイス言語選択オプションです。アプリケーションはロシア語と英語の2つの言語をサポートしています。言語選択は図4に示されています。

図4 インターフェイス言語選択

言語の変更は、ChangeLanguage()メソッドを介して実行されます。テキストコンポーネントはその論理に従って置き換えられます。メソッドコードはとても単純です。これがイベントハンドラでのアプリケーションです。

//--- コンボボックス内の項目の選択
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_COMBOBOX_ITEM)
     {
      //--- 時間枠の変更
      if(ChangePeriod1(lparam))
         Update(true);
      //--- インターフェイス言語の変更
      if(ChangeLanguage(lparam))
         Update(true);
     }

コードからわかるように、コンボボックスの項目が選択されると、言語変更メソッドはドロップダウンメニューの項目のどれを選択するかを決定し、適切な言語インデックスを設定します。

//+------------------------------------------------------------------+
//| インターフェイス言語の変更                                           |
//+------------------------------------------------------------------+
bool CProgram::ChangeLanguage(const long id)
  {
//--- 要素IDを確認する
   if(id!=m_lang_setting.Id())
      return(false);
   m_lang_index=m_lang_setting.GetListViewPointer().SelectedItemIndex();
//---
   if(m_lang_index==0)
     ....

次のセクションでは、テスト用のパターンが生成される基本ローソク足タイプの選択について説明します。これには11種類あります。このコントロールは、使用されているローソク足の種類とチェックボックスの名前のリストとして実装されています。 実装にはCreateListView()メソッドを使用しました。

//+------------------------------------------------------------------+
//| リストを作成する                                                    |
//+------------------------------------------------------------------+
bool CProgram::CreateListView(const int x_gap,const int y_gap)
  {
//--- リストビューのサイズ
#define CANDLE_TOTAL 11
//--- メインコントロールへのポインタを格納する
   m_listview1.MainPointer(m_tabs1);
//--- タブに取り付ける
   m_tabs1.AddToElementsArray(2,m_listview1);
//--- プロパティ
   m_listview1.XSize(175);
   m_listview1.YSize(250);
   m_listview1.ItemYSize(19);
   m_listview1.LabelXGap(25);
   m_listview1.LightsHover(true);
   m_listview1.CheckBoxMode(true);
   m_listview1.ListSize(CANDLE_TOTAL);
   m_listview1.AutoYResizeMode(true);
   m_listview1.AutoYResizeBottomOffset(10);
   m_listview1.FontSize(10);
//--- リストビューにデータを書き入れる
   string cand_name[CANDLE_TOTAL]=
     {
      "Long — bullish",
      "Long — bearish",
      "Short — bullish",
      "Short — bearish",
      "Spinning Top — bullish",
      "Spinning Top — bearish",
      "Doji",
      "Marubozu — bullish",
      "Marubozu — bearish",
      "Hammer — bullish",
      "Hammer — bearish"
     };
   for(int r=0; r<CANDLE_TOTAL; r++)
     {
      m_listview1.SetValue(r,(string)(r+1)+". "+cand_name[r]);
     }
//--- リストビューを作成する
   if(!m_listview1.CreateListView(x_gap,y_gap))
      return(false);
//--- 要素へのポインタをベースに追加する
   CWndContainer::AddToElementsArray(0,m_listview1);
   return(true);
  }

次の2つのコントロールは基本ローソク足タイプのリストに直接関係しています。最初のコントロールは、繰り返しを有効または無効にするスイッチです。タスク定義のセクションで既に説明したように、繰り返しは、サイズに関係なく、1つのローソク足タイプだけで構成されるパターンに関連しています。 

図5 分析されたローソク足の種類と繰り返しモードの選択

Repeatスイッチの作成を担当するメソッドはCreateDualButton()と呼ばれます。

//+------------------------------------------------------------------+
//| Repeatスイッチの作成                                                 |
//+------------------------------------------------------------------+
bool CProgram::CreateDualButton(CButton &lbutton,CButton &rbutton,const int x_gap,const int y_gap,const string ltext,const string rtext)
  {
   CreateButton(lbutton,x_gap,y_gap,ltext);
   CreateButton(rbutton,x_gap+99,y_gap,rtext);
   return(true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CProgram::CreateButton(CButton &button,const int x_gap,const int y_gap,const string text)
  {
//--- メインコントロールへのポインタを保存する
   button.MainPointer(m_tabs1);
//--- タブに取り付ける
   m_tabs1.AddToElementsArray(2,button);
//--- プロパティ
   button.XSize(100);
   button.YSize(30);
   button.Font("Trebuchet");
   button.FontSize(10);
   button.IsCenterText(true);
   button.BorderColor(C'0,100,255');
   button.BackColor(clrAliceBlue);
   button.BackColorLocked(C'50,180,75');
   button.BorderColorLocked(C'50,180,75');
   button.LabelColorLocked(clrWhite);
//--- コントロールの作成
   if(!button.CreateButton(text,x_gap,y_gap))
      return(false);
//--- 要素へのポインタをベースに追加する
   CWndContainer::AddToElementsArray(0,button);
   return(true);
  }

コントロール操作の設定は、左クリックイベントで追跡されます。

   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
     {
      ....
      //--- ボタンが押下された場合
      if(lparam==m_button7.Id())
        {
         m_button7.IsLocked(true);
         m_button8.IsLocked(false);
        }
      else if(lparam==m_button8.Id())
        {
         m_button7.IsLocked(false);
         m_button8.IsLocked(true);
        }

アプリケーションの視覚部分を分析したので、次に計算部分に進みましょう。まず、最小限の設定、一連のアクション、およびこれらのアクションの処理方法を決定する必要があります。

ステップ1: 入力データの設定

アプリケーションを開始する前に、分析用のパターンが生成される基本ローソク足タイプを選択する必要があります。次に、繰り返しモードが有効になっているかどうかを選択します。繰り返しモードでは、任意のサイズのパターンの作成に1つのローソク足タイプのみを使用します。次に、1パターンの中のローソク足の数を選択します。これには、1、2、または3本のローソク足のパターンが含まれます。2本パターンまたは3本パターンを生成するには、少なくとも2本の基本ローソク足を選択する必要があります。ローソク足の少ないパターンを生成しようとすると、アプリケーションはエラーを返します(図6を参照)。

図6 エラー: 2本パターンに対して1個のローソク足タイプのみが選択されている

ステップ2: [AutoSearch]タブの使用

適切な入力パラメータを設定したら、自動検索に切り替えてテスト用の記号を選択します。このタブに表示される商品の機能を詳しく見てみましょう。

  • 分析対象の通貨記号を選択して検索します。入力フィールドに、銘柄の一部または指定した希望のものをコンマで区切って入力し[Search]ボタンをクリックします。主要通貨ペアを示す定義済みフレーズ「Major」を使用することもできます。[気配値情報]ウィンドウで利用可能なすべての銘柄を表示するには、左上隅のチェックボックスをオフにする必要があります。これにより、検索ウィンドウでのフィルタリングが無効になります。
  • 次に、ドロップダウンリストから希望の時間枠を選択し、選択した時間枠のローソク足の数としてサンプル範囲を選択します。
  • 必要な商品またはリストを選択したら、現在のものをクリックして分析を開始します。その後、アプリケーションはステップ1で構成されたパターンを生成し、適切な計算を実行してデータを表に表示します。表でデータを受信した後、時間枠を変更すると、データがリアルタイムで再計算されます。

結果のデータ表を詳細に見てみましょう。これは、これから検討するアルゴリズムの計算および動作原理を理解するのに役立ちます。


図7 EURUSDペアのデータ計算例  

図7からわかるように、分析された通貨ペアを含む行が銘柄表で選択されています。M15の時間枠と8000 15分ローソク足のサンプル範囲は、右側の上部に表示されています。結果表には6列あります。残りの列は最初の記事のインターフェイスプロトタイプの開発セクションで説明したので、ここでは最初の列のみを考察します。

最初の列は[Set]です。下の行では、値は[1,1,2]の形式で表示されます。角かっこ内の3つの数字は、3つのローソク足のパターンが使用されていることを意味します。パターンは、角括弧で指定された順序で基本ローソク足タイプ1と2で構成されています。使用されているローソク足の数は、[Used candles](使用されるローソク足)セクションの中の[Settings](設定)タブにあります。

図8 パターン生成に使用されるローソク足のリストと数  

これでアプリケーションの構成方法と起動方法がわかったので、内部操作ロジックの検討に進むことができます。入力データを設定した後、銘柄表の通貨商品をクリックします。表の項目のクリックを処理すると、ChangeSymbol2()メソッドが呼び出されます。

//--- リストまたは表の項目の押下イベント
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_LIST_ITEM)
     {
      //--- 銘柄の変更
      if(ChangeSymbol1(lparam))
         Update(true);
      if(ChangeSymbol2(lparam))
         m_table2.Update(true);
     }

このメソッドでは、ステータスバーに情報値を設定するほかに、さらに2つのメソッドを含みます。

//+------------------------------------------------------------------+
//| 銘柄の変更                                                         |
//+------------------------------------------------------------------+
bool CProgram::ChangeSymbol2(const long id)
  {
//--- 要素IDを確認する
   if(id!=m_symb_table2.Id())
      return(false);
//--- 行が強調表示されていない場合は終了する
   if(m_symb_table2.SelectedItem()==WRONG_VALUE)
     {
      //--- ステータスバーに完全な銘柄説明を表示する
      m_status_bar.SetValue(0,"No symbol selected for analysis");
      m_status_bar.GetItemPointer(0).Update(true);
      return(false);
     }
//--- 銘柄を取得する
   string symbol=m_symb_table2.GetValue(0,m_symb_table2.SelectedItem());
//--- ステータスバーに完全な銘柄説明を表示する
   string val=(m_lang_index==0)?"Выбранный символ: ":"Selected symbol: ";
   m_status_bar.SetValue(0,val+::SymbolInfoString(symbol,SYMBOL_DESCRIPTION));
   m_status_bar.GetItemPointer(0).Update(true);
   if(!BuildingAutoSearchTable())
      return(false);
   GetPatternType(symbol,m_total_combination);
   return(true);
  }

初めのメソッドはBuildingAutoSearchTable()です。[Settings](設定)タブの[Used candles](使用されるローソク足)セクション(図8)で選択された基本ローソク足のリストからパターンを作成し、それらを結果表の最初の列に表示します。

//+------------------------------------------------------------------+
//| パターン自動検索テーブルを再構築する                                   |
//+------------------------------------------------------------------+
bool CProgram::BuildingAutoSearchTable(void)
  {
//---
   if(!GetCandleCombitaion())
     {
      if(m_lang_index==0)
         MessageBox("Число выбранных свечей меньше размера исследуемого паттерна!","Ошибка");
      else if(m_lang_index==1)
         MessageBox("The number of selected candles is less than the size of the studied pattern!","Error");
      return(false);
     }
//--- すべての行を削除する
   m_table2.DeleteAllRows();
//--- 行数を銘柄数で設定する
   for(int i=0; i<ArraySize(m_total_combination); i++)
     {
      m_table2.AddRow(i);
      m_table2.SetValue(0,i,m_total_combination[i]);
     }
   m_table2.DeleteRow(ArraySize(m_total_combination));
//--- 表を更新する
   m_table2.Update(true);
   m_table2.GetScrollVPointer().Update(true);
   m_table2.GetScrollHPointer().Update(true);
   return(true);
  }
//+------------------------------------------------------------------+
//| 基本ローソク足に基づくパターンの生成                                   |
//+------------------------------------------------------------------+
bool CProgram::GetCandleCombitaion(void)
  {
   string candlenumber[];
   int selected_candles=0,n;
   ArrayResize(candlenumber,m_total_candles);
//---
   for(int i=0;i<m_total_candles;i++)
     {
      if(m_listview1.GetState(i))
        {
         candlenumber[selected_candles]=(string)(i+1);
         selected_candles++;
        }
     }

   if((m_pattern_size==2 && selected_candles<2) || (m_pattern_size==3 && selected_candles<2) || selected_candles<1)
      return(false);
//--- 組み合わせ数の計算
   if(m_pattern_size>1)
      n=(m_button7.IsLocked())?(int)MathPow(selected_candles,m_pattern_size):(int)MathPow(selected_candles,m_pattern_size)-selected_candles;
   else
      n=selected_candles;
   ArrayResize(m_total_combination,n);

   n=0;
//--- 1本のローソク足のセット
   if(m_pattern_size==1)
     {
      for(int i=0;i<selected_candles;i++)
         m_total_combination[i]="["+candlenumber[i]+"]";
     }
//--- 2本のローソク足のセット
   else if(m_pattern_size==2)
     {
      //--- 繰り返しモードが有効
      if(m_button7.IsLocked())
        {
         for(int i=0;i<selected_candles;i++)
           {
            for(int j=0;j<selected_candles;j++)
              {
               m_total_combination[n]="["+candlenumber[i]+","+candlenumber[j]+"]";
               n++;
              }
           }
        }
      //--- 繰り返しモードが無効
      else if(m_button8.IsLocked())
        {
         for(int i=0;i<selected_candles;i++)
           {
            for(int j=0;j<selected_candles;j++)
              {
               if(j!=i)
                 {
                  m_total_combination[n]="["+candlenumber[i]+","+candlenumber[j]+"]";
                  n++;
                 }
              }
           }
        }
     }
//--- 3本のローソク足のセット
   else if(m_pattern_size==3)
     {
      //--- 繰り返しモードが有効
      if(m_button7.IsLocked())
        {
         for(int i=0;i<selected_candles;i++)
           {
            for(int j=0;j<selected_candles;j++)
              {
               for(int k=0;k<selected_candles;k++)
                 {
                  m_total_combination[n]="["+candlenumber[i]+","+candlenumber[j]+","+candlenumber[k]+"]";
                  n++;
                 }
              }
           }
        }
      //--- 繰り返しモードが無効
      else if(m_button8.IsLocked())
        {
         for(int i=0;i<selected_candles;i++)
           {
            for(int j=0;j<selected_candles;j++)
               for(int k=0;k<selected_candles;k++)
                 {
                  if(i==j && i==k)
                     continue;
                  m_total_combination[n]="["+candlenumber[i]+","+candlenumber[j]+","+candlenumber[k]+"]";
                  n++;
                 }
           }
        }
     }
   return(true);
  }

ローソク足セットに基づくパターンの作成は、GetCandleCombination()メソッドによって実行されます。このメソッドの目的は、選択したローソク足のシーケンス番号に基づいて、繰り返しの有無にかかわらず、パターンセクションのローソク足の数で選択したサイズを考慮して、基本ローソク足のすべての可能な組み合わせを表示することです。 

すべての組み合わせが文字列配列m_total_combitaion[]に書き込まれ、データはBuildingAutoSearchTable()メソッドの結果表に追加されます。

BuildingAutoSearchTable()の後に呼び出される2番目のメソッドは、生成されたパターンの結果リスト上の他のデータベースの計算と表示を担当します。GetPatternType()メソッドをもっと詳しく考えてみましょう。これは最初の記事で慈善定義パターンの計算に使用されていましたが、単純化されています。このタスクの目的は、チャート上の事前設定パターンを認識して分析することです。このメソッドは既存のパターンと生成されたパターンの検索に使用されるため、メソッドの多重定義が実装されました。

   //--- パターンの認識
   bool              GetPatternType(const string symbol);
   bool              GetPatternType(const string symbol,string &total_combination[]);

2番目の変形では、生成されたパターンを持つ以前に作成された文字列データ配列を使用します。このメソッドの目的は、チャート上で生成されたパターンを識別して評価し、その効率を計算することです。アイデアとアルゴリズムは最初の記事の「タスク定義」セクションで説明されているため、ここでは省きます。

発見されたパターン効率は、配列を使用して以前に評価され、上昇および下降動向についてカテゴリ推定値A、B、Cが加えられました。本稿では、配列を構造体に変換して、コードを短くすることができました。構造体は次のとおりです。

struct RATING_SET
  {
   int               a_uptrend;
   int               b_uptrend;
   int               c_uptrend;
   int               a_dntrend;
   int               b_dntrend;
   int               c_dntrend;
  };

 ここでの作業には生成されたパターンのそれぞれについてこの一連の推定値が必要であるため、構造体のRATING_SET配列はメソッドの先頭で宣言されています。配列サイズは、生成されたパターンの数または文字列配列m_total_combitaion []のサイズに対応します。

   RATING_SET ratings[];

//---
   total_patterns=ArraySize(total_combination);
...
   ArrayResize(ratings,total_patterns);

この配列には、生成されたすべてのパターンが格納されますが、これらは結果として表の最初の列に表示される文字列として表示されます。そのため、次の段階では、各文字列から使用されている基本ローソク足パターンのインデックスを抽出し、CANDLE_STRUCTUREからのローソク足タイプに変換します。

struct CANDLE_STRUCTURE
  {
   double            open,high,low,close;       // OHLC
   TYPE_TREND        trend;                     // トレンド
   bool              bull;                      // 強気ローソク足
   double            bodysize;                  // 弱気ローソク足
   TYPE_CANDLESTICK  type;                      // ローソク足タイプ
  };

このために、いくつか変換を行います。さらに、ローソク足インデックスをタイプに変換するのに役立つ追加のメソッドを検討します。

//---
   for(int i=0;i<total_patterns;i++)
     {
      StringReplace(total_combination[i],"[","");
      StringReplace(total_combination[i],"]","");
      if(m_pattern_size>1)
        {
         ushort sep=StringGetCharacter(",",0);
         StringSplit(total_combination[i],sep,elements);
        }
      ZeroMemory(ratings[i]);
      m_pattern_total[i]=0;
      if(m_pattern_size==1)
         IndexToPatternType(cand1[i],(int)total_combination[i]);
      else if(m_pattern_size==2)
        {
         IndexToPatternType(cand1[i],(int)elements[0]);
         IndexToPatternType(cand2[i],(int)elements[1]);
        }
      else if(m_pattern_size==3)
        {
         IndexToPatternType(cand1[i],(int)elements[0]);
         IndexToPatternType(cand2[i],(int)elements[1]);
         IndexToPatternType(cand3[i],(int)elements[2]);
        }
     }

生成されたパターンの各文字列値をループ処理し、角かっこを削除し、区切り文字「,」に基づいてStringSplit()を適用して、elements []配列に情報を追加します。1本パターンではコンマがなく角括弧を削除するだけでよいため、この手順は複数ローソク足で構成されるパターンに適用されることに注意してください。ここでIndexToPatternType()メソッドを考えてみましょう。生成されたパターンの配列からデータを書き入れて処理するためにCANDLE_STRUCTUREを入力します。

void CProgram::IndexToPatternType(CANDLE_STRUCTURE &res,const int index)
  {
//--- ロング - 強気
   if(index==1)
     {
      res.bull=true;
      res.type=CAND_LONG;
     }
//--- ロング - 弱気
   else if(index==2)
     {
      res.bull=false;
      res.type=CAND_LONG;
     }
//--- ショート - 強気
   else if(index==3)
     {
      res.bull=true;
      res.type=CAND_SHORT;
     }
//--- ショート - 弱気
   else if(index==4)
     {
      res.bull=false;
      res.type=CAND_SHORT;
     }
//--- コマ(極線) - 強気
   else if(index==5)
     {
      res.bull=true;
      res.type=CAND_SPIN_TOP;
     }
//--- コマ(極線) - 弱気
   else if(index==6)
     {
      res.bull=false;
      res.type=CAND_SPIN_TOP;
     }
//--- 同事
   else if(index==7)
     {
      res.bull=true;
      res.type=CAND_DOJI;
     }
//--- 丸坊主 - 強気
   else if(index==8)
     {
      res.bull=true;
      res.type=CAND_MARIBOZU;
     }
//--- 丸坊主 - 弱気
   else if(index==9)
     {
      res.bull=false;
      res.type=CAND_MARIBOZU;
     }
//--- 唐笠 - 強気
   else if(index==10)
     {
      res.bull=true;
      res.type=CAND_HAMMER;
     }
//--- 唐笠 - 弱気
   else if(index==11)
     {
      res.bull=false;
      res.type=CAND_HAMMER;
     }
  }

パターンサイズに応じて、1、2、または3つのCANDLE_STRUCTURE(cand1、cand2、cand3)が書き入れられます。以下のコードをご覧ください。

if(m_pattern_size==1)
         IndexToPatternType(cand1[i],(int)total_combination[i]);
      else if(m_pattern_size==2)
        {
         IndexToPatternType(cand1[i],(int)elements[0]);
         IndexToPatternType(cand2[i],(int)elements[1]);
        }
      else if(m_pattern_size==3)
        {
         IndexToPatternType(cand1[i],(int)elements[0]);
         IndexToPatternType(cand2[i],(int)elements[1]);
         IndexToPatternType(cand3[i],(int)elements[2]);
        }

これにより、チャート上のパターンのサイズに関係なく、必要な数のローソク足を即座に分析できます。 

1本パターンの場合、それぞれ特定の場合に1本のローソク足だけが分析と計算に使用され、2本および3本ロパターンではセット全体が使用されます。例えば、サンプリング範囲が2000のローソク足だとすると、1本パターンのではセットは2000番目のローソク足1本で構成され、2本パターンでは2000番目と1999番目のローソク足で構成されるといった具合です。 

次に、以下のGetPatternType()メソッドのフラグメントを考察します。これは、チャート上に生成された各パターンを見つける役割を果たします。

//---
   for(int i=m_range_total2;i>5;i--)
     {
      if(m_pattern_size==1)
        {
         //--- 現在のローソク足タイプを取得する
         GetCandleType(symbol,cur_cand,m_timeframe2,i);                                         // 現在のローソク足
         //---
         for(int j=0;j<total_patterns;j++)
           {
            if(cur_cand.type==cand1[j].type && cur_cand.bull==cand1[j].bull)
              {
               m_pattern_total[j]++;
               GetCategory(symbol,i-3,ratings[j],m_timeframe2);
              }
           }
        }
      else if(m_pattern_size==2)
        {
         //--- 現在のローソク足タイプを取得する
         GetCandleType(symbol,prev_cand,m_timeframe2,i);                                        // 1つ前のローソク足
         GetCandleType(symbol,cur_cand,m_timeframe2,i-1);                                       // 現在のローソク足
         //---
         for(int j=0;j<total_patterns;j++)
           {
            if(cur_cand.type==cand1[j].type && cur_cand.bull==cand1[j].bull && 
               prev_cand.type==cand2[j].type && prev_cand.bull==cand2[j].bull)
              {
               m_pattern_total[j]++;
               GetCategory(symbol,i-4,ratings[j],m_timeframe2);
              }
           }
        }
      else if(m_pattern_size==3)
        {
         //--- 現在のローソク足タイプを取得する
         GetCandleType(symbol,prev_cand2,m_timeframe2,i);                                       // 1つ前のローソク足
         GetCandleType(symbol,prev_cand,m_timeframe2,i-1);                                      // 1つ前のローソク足
         GetCandleType(symbol,cur_cand,m_timeframe2,i-2);                                       // 現在のローソク足
         //---
         for(int j=0;j<total_patterns;j++)
           {
            if(cur_cand.type==cand1[j].type && cur_cand.bull==cand1[j].bull && 
               prev_cand.type==cand2[j].type && prev_cand.bull==cand2[j].bull && 
               prev_cand2.type==cand3[j].type && prev_cand2.bull==cand3[j].bull)
              {
               m_pattern_total[j]++;
               GetCategory(symbol,i-5,ratings[j],m_timeframe2);
              }
           }
        }
     }

上記のコードからわかるように、ループは最初の部分にあり、6番目のローソク足で停止しています。何故でしょうか。最初の記事では、パターン効率を分析するために、パターン形成後に価格がどう動くかとパターンが何を予測するかを特定し、予測の頻度と確率を調べる必要があると述べました。この評価では、パターンに続く3本のローソク足で価格変動の分析を実施しました。現在のゼロローソク足はまだ完成していないため、分析されません。 

図9 パターン効率評価の計算 

図9には3本パターンが示されています。効率を評価するには、ゼロローソク足以外のローソク足がさらに3本必要です。したがって、現在のパターンについてこれらの条件を満たすために、パターン内の最初のローソク足は6の最小インデックスを持つことができます。 

パターンを検索し、その数を数え、A、B、Cのカテゴリで評価した後、受信したデータを処理して結果を表に追加する必要があります。これらの計算はCoefCalculation()メソッドで実行されます。

//---
   for(int i=0;i<total_patterns;i++)
      CoefCalculation(m_table2,i,ratings[i],m_pattern_total[i]);

 以下はメソッド引数です。

  • m_table2 — 生成された各パターンの計算結果が追加される表へのリンク
  • i — 表の列
  • ratings[i] — 各パターンに対するカテゴリベースの評価のセットを含む、構造RATING_SETの配列
  • m_pattern_total[i] — 各タイプの見つかったパターンの数を含む配列

このメソッドをもっと詳しく考えてみましょう。

//+------------------------------------------------------------------+
//| 効率評価係数の計算                                                       |
//+------------------------------------------------------------------+
bool CProgram::CoefCalculation(CTable &table,const int row,RATING_SET &rate,int found)
  {
   double p1,p2,k1,k2;
   int sum1=0,sum2=0;
   sum1=rate.a_uptrend+rate.b_uptrend+rate.c_uptrend;
   sum2=rate.a_dntrend+rate.b_dntrend+rate.c_dntrend;
//---
   p1=(found>0)?NormalizeDouble((double)sum1/found*100,2):0;
   p2=(found>0)?NormalizeDouble((double)sum2/found*100,2):0;
   k1=(found>0)?NormalizeDouble((m_k1*rate.a_uptrend+m_k2*rate.b_uptrend+m_k3*rate.c_uptrend)/found,3):0;
   k2=(found>0)?NormalizeDouble((m_k1*rate.a_dntrend+m_k2*rate.b_dntrend+m_k3*rate.c_dntrend)/found,3):0;

   table.SetValue(1,row,(string)found);
   table.SetValue(2,row,(string)((double)found/m_range_total2*100),2);
   table.SetValue(3,row,(string)p1,2);
   table.SetValue(4,row,(string)p2,2);
   table.SetValue(5,row,(string)k1,2);
   table.SetValue(6,row,(string)k2,2);
//--- 表を更新する
   table.Update(true);
   table.GetScrollVPointer().Update(true);
   table.GetScrollHPointer().Update(true);
   return(true);
  }

メソッドの実装からわかるように、構造体の使用によってパターン分析係数がどのように計算されるかを明確に見ることができます。

アプリケーション操作のデモンストレーション

例として、生成されたパターンのいくつかを異なるパラメータでテストします。

ステップ1: シンプルなローソク足モデルの選択

まず、[Used candlesticks](使用されるローソク足)セクションですべての可能なシンプルなローソク足モデルを選択し、[With repetitions](繰り返しを伴う)を選択して[The number of candlesticks in a pattern](パターン内のローソク足の数)を1に設定する必要があります。ポイント単位のトレンド閾値は200に設定されます。以下が設定です。

図10 生成されたパターンを分析するための最初の設定ステップ

次に[AutoSearch]タブに移動し、検索ボックスに「Major」と入力して[Search]をクリックします。次に時間枠をН1に設定し、通貨ペアGBPUSDを選択します。これがテスト結果です。

図11 生成された1本パターンのテスト結果

最も頻繁に使われるローソク足タイプを6個選択します。これらは降順で1、2、5、6、3、4です。

ステップ2: 2本のローソク足から構成されるパターンのテスト

ここで1本パターンに基づいて2本パターンを作成します。[Settings]タブに移動し、チェックボックス7~11をオフにします。今回は、モードを[No Repeat](繰り返しなし)に設定し、[Number of candles in the pattern](パターン内のローソク足の数)を2に設定します。上の構成を図12に示します。

図12 生成された2本パターンのテスト構成  

自動検索に戻り、GBPUSDをクリックします。これは選択したローソク足のさまざまな組み合わせを生成し、それらの評価を提供します。しかし、[Threshold trend value](閾値トレンド値)が低い場合、特に時間枠が長い場合、価格変動の結果はほとんど同じです。閾値を大きくすると、パターン検索の条件を厳しく設定できます。例えば、以下は閾値が400に等しい場合の結果です。

図13 トレンド閾値を上げてテストした結果

得られた結果の中で、一方向への大きな価格変動およびそのなん分の一かの規模を持つ反対方向への変動を見つけることを試みました。図13からわかるように、この状況は[1,4]と[2,6]で2回発生しました。これらは、ロング(強気) - ショート(弱気)およびロング(弱気) - コマ(極線)(弱気)のパターンです。2番目のパターン変形は、その発生頻度がほぼ数倍高いので、より好ましいものです。

ここで、3本のローソク足から構成されるパターンをテストしましょう。すべての可能な単純なモデルオプションでもパターン変形はあまりにも多くあるため、前のテストでしばしば遭遇した4タイプ(1、2、5、6)のみを使います。正しく設定された[Settings]タブは次のようになります。

図14 生成された3本パターンのテスト構成

トレンド値の閾値は400のままです。次に[AutoSearch]タブを開き、再度[GBPUSD]をクリックします。ここでは、パフォーマンスの良いパターンを選択するための同じ原則が使用されています。一方向の価格変動が反対方向の変動よりも大きい場合です。これは効率係数からわかります。例えば、2回続けて、非常に優れた係数と確率パラメータを持つ非常に興味深い結果に遭遇しました。

図15 生成された3本パターンのテスト結果

これらはパターン[2,5,2]と次の[2,5,5]で、ロング(弱気) - コマ(極線)(強気) - ロング(弱気)とロング(弱気) - コマ(極線)(強気) - コマ(極線) (強気)です。最初のローソク足パターンは、上昇トレンドと大きな効率係数の高い確率を示しました。2番目のものは良い一方向確率を持っていますが、効率係数は少し低いです。 

多数のパラメータの組み合わせによって他の興味深い結果がもたらされる可能性があります。データ処理に時間がかかる可能性があるため、テスト時に11個のローソク足タイプをすべて同時に使用することはお勧めできません。サンプル範囲、時間枠、トレンド閾値、および基本ローソク足タイプの個々の設定を考慮に入れないでも、分析のためのパターンの可能な最大の組み合わせは1463に等しいです。このような大規模な分析には多くの時間がかかります。

終わりに

以下の添付ファイルには、説明されたすべてのファイルがフォルダに正しく分類されています。正しく動作させるためには、MQL5フォルダをターミナルフォルダーに保存するだけです。

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

#
 名称
種類
説明
1
PatternAnalyzer.mq5 グラフィカルインターフェイス
 ローソク足パターンを分析するためのツールバー
2 MainWindow.mqh コードベース  GUIライブラリ
3 Program.mqh コードベース  インターフェイスと計算要素を作成するためのメソッドのライブラリ