MetaTrader 5をダウンロードする

インジケーターへのエントリの解決

25 12月 2017, 13:05
Dmitriy Gizlyk
0
822

イントロダクション

勝てるトレーダーを見て、同じような戦略に従おうとしていますか。 もしくは、自分のトレード履歴を見て、負けトレードを減らす方法を考えていますか。 少なくともどちらかの質問にはポジティブな返答であることを期待しています。 この記事では、トレード履歴からインジケーターに落とし込み、どのインジケーターが役に立つかを判断する方法を考察します。

1. 問題の定義

以前の記事では、カルマンのフィルタベースのEAの構築について説明しました。 テストにおいて利益を示したが、同時に2つの戦略上のネックがありました。つまり、遅い決済とレンジ相場における負けトレードです。

したがって、今回の目的は、この戦略下で負けトレードの数を減らすことです。 そのためには、ポジションの建玉の瞬間にインジケーターの値を保存します。 その後、分析を行い、トレード結果とインジケーターの値を比較します。 後は、トレードのパフォーマンスを向上させるために役立つインジケーターの間で選択することです。

まずは行動計画を立てましょう。

  1. テスト期間を決定 テストしてレポートを保存
  2. テストレポートを解析し、トレードの配列を作成(操作結果を含む)
  3. 使用するインジケーターの一覧とデータ保存形式を決定 さらにアプリケーションのクラスを準備
  4. 結果出力用のレポートフォームを準備します。
  5. 分析 EA を構築します。
  6. ストラテジーテスターで対象EA を起動し、レポートを分析します。
  7. EA に必要なインジケーターを追加します。
  8. 更新された EA をテストし、結果を比較します。

2. 分析された EA の最初のテスト

上記の記事では、EA はテストの1ヶ月以内に150のトレードを行った。 これは、統計解析には不十分です。 テスト期間を8倍に増やします。 最適化なしで、3120足 (約3ヶ月) の自己回帰関数の構築期間を設定し、テストを開始します。

最初のテスト。最初のテスト

テスト結果では明らかに損失になる資産チャートになりました。 一般的に、勝ちトレードは 34% 未満になりました。 ただし、平均利益は 45% 平均損失を上回っています。 これは、テスト期間中において利益を得るには不足しています。

最初のテスト

この価格表は、明確に定義されたトレンドがない場合(レンジ)、EAが損失になるポジションを開き、その後決済することを示しています。 今回のタスクは、そのようなトレードの数を減らす、可能であれば、完全に除外することです。

テストチャート

まず、テストレポートを保存して、さらに処理を行う必要があります。 ただし、セキュリティ上の理由から、ファイルを使用した MQL5 タスクでは厳密に制御されているという意味合いがあります。 MQL5 ツールを使用して操作を実行するためのファイルが "サンドボックス" ファイルにあることを確認してください。 よって、レポートはそこに保存する必要があります。 しかし、ストラテジーテスターでプログラムを起動するので、各エージェントがその "サンドボックス" で動作することを考慮する必要があります。 したがって、任意のエージェントでテスト中にプログラムがレポートにアクセスできるようにするため、共有ターミナルフォルダに保存します。

クライアントターミナルの共有フォルダへのパスを確認するには、メタエディタ の "ファイル" メニューを開き、[共通データフォルダを開く] を選択します。

"サンドボックス" へのパス

開いたウィンドウで、「ファイル」フォルダを入力します。

"サンドボックス" へのパス

次に、"Ctrl + C" を押して、完全なパスラインを exchange バッファにコピーします。

"サンドボックス" へのパス

"サンドボックス" へのパスが知られており、テストレポートを保存することができます。 そのためには、「ストラテジーテスター」で「結果」を選択し、そのスペースでマウスの右ボタンをクリックします。 表示されるメニューで、"Report"-> "HTML (Internet Explorer)" を選択します。

レポートを保存します。

操作を実行すると、ファイル保存用のシステムウィンドウが開きます。 まず、ファイル名の入力フィールドに "サンドボックス" へのパスを入れて、"保存" を押してください。 この操作により、ファイル保存用のフォルダが変更されます。

レポートの保存

次の手順では、テストレポートを保存する名前を指定し、ファイルを保存します。

レポートの保存

「サンドボックス」でレポートを保存した後、次のフェーズに進み、分析にトレード配列を作成します。

3. トレード配列を作成する

3.1. 解析の一般的な概念

前のセクションでは、EA のテストレポートを保存しました。 これを処理するための便利なトレードの配列を形成するつもりです。 ブラウザではトレードの一覧が表示されますが、MQL5 プログラムは html ファイルから直接データ配列をダウンロードすることはできません。 したがって、レポートの解析を実装する必要があります。

レポートのトレードリスト

実質的には、html ファイルは、その書式とデザインを記述するタグで区切られたテキストです。 レポートをテキストエディタで開いたことで、レポート内のすべてのデータが2つのデータテーブルに分割されることを意味する2つのタグ "<table>" を見つけることができます。 トレードに関する情報は2テーブルにあります。 その始まりには、オーダーに関する情報とし、トレードに関する情報があります。

HTML-レポートのビュー

表の行は、"<tr> </tr>" というタグでマークアップされています。 行では、"<td> </td>" というタグによってセルに分割されます。

3.2. トレードの情報を保存するためのクラス

レポートでデータの表示形式を決定しました。 では、配列内のデータ保存形式に進みましょう。 分析された EA が1つのシンボルでのみ動作する限り、シンボル名は保存されません。 それもかかわらず、インジケーターの初期化に必要となります。 最後に、トレードの記録的構造は次のようになります。

  • position open time;
  • position open volume;
  • trade direction;
  • position close volume;
  • commission amount;
  • swap amount;
  • profit amount.

このタスクの主な側面を決定しました。 コードを書き始めましょう。 まず、トレードクラスの CDeal を確認します。

class CDeal       :  public CObject
  {
private:
   datetime          OpenTime;         //オープンポジションの時間
   double            OpenedVolume;     //開いたポジションのボリューム
   ENUM_POSITION_TYPE Direct;          //オープンポジションのタイプ
   double            ClosedVolume;     //クローズドボリューム
   double            Comission;        //手数料
   double            Swap;             //ポジションの入れ替え
   double            Profit;           //ポジションの利益
   
public:
                     CDeal();
                    ~CDeal();
  };

新しいオープントレードを記録するときにクラスを初期化します。ポジションの開始時, トレードのボリュームと方向はすでに知っているものとします。 したがって、初期化関数のパラメータに値とコミッションが伝達されます。(可能な場合) 初期化時に他のパラメータをゼロにします。 その結果、クラス初期化関数は次のようになります。

CDeal::CDeal(ENUM_POSITION_TYPE type,datetime time,double volume,double comission=0.0)  : ClosedVolume(0),
                                                                                          Swap(0),
                                                                                          Profit(0)
  {
   OpenTime      = time;
   OpenedVolume  = volume;
   Direct        = type;
   Comission     = comission;
  }

それ以上のタスクでは、すでに保存されたトレードの状態を確認する必要があります。 これを行うためには、トレードがすでに閉じているかどうかをチェックする IsClosed 関数を作成します。 トレードの開始および決済のボリュームで比較されます。 等しい場合は、トレードが決済され、この関数は "true" の値を返すことを意味します。 トレードが閉じられていない場合、関数は "false" を返し、相場に残っているボリュームが返されます。

bool CDeal::IsClosed(double &opened_volume)
  {
   opened_volume=OpenedVolume-ClosedVolume;
   return (opened_volume<=0);
  }

トレードの状態だけを確認する必要がある場合には、ボリュームを見つけるために必要はありません。同じ名前でもう一つの関数を作ります。

boolCDeal:: IsClosed (void)
  {
   double opened_volume;
   return IsClosed(opened_volume);
  }

正しくトレードを閉じるために、そのタイプを知っている必要があります。 "Type" メソッドは、"private" 変数 "Direct" の値を返します。 この関数はかなり短いため、クラス本体で再記述することができます。

ENUM_POSITION_TYPE Type(void) {  return Direct; }

ステータスがチェックされた後、トレードを閉じる必要があります。 それを行うために "Close" 関数を作成します。 次のパラメータが渡されます。すはわち、クロージングボリューム、トレード利益、コミッションと累積スワップ。 この関数は、渡されたボリュームがないトレード量を超えた場合に "false" を返します。 それ以外の場合は、渡されたパラメータが対応するクラス変数に保存され、この関数は "true" を返します。

bool CDeal::Close(double volume,double profit,double comission=0.0,double swap=0.0)
  {
   if((OpenedVolume-ClosedVolume)<volume)
      return false;
   ClosedVolume   += volume;
   Profit         += profit;
   Comission      += comission;
   Swap           += swap;
   return true;
  }

トレードを分析するときにリクエスト時にトレード利益を返す関数が必要になります。 その関数GetProfitを呼び出しましょう。

double CDeal::GetProfit(void)
  {
   return (Comission+Swap+Profit);
  }

また、インジケーターのステータスに関するデータをタイムリーに受けとるためには、トレード時間を知る必要があります。 このために、"GetTime" 関数を作成します。

datetime          GetTime(void)  {  return OpenTime;  }

3.3. レポート解析のクラス

各トレードに関する情報を保存するためのクラスを作成したら、すぐに次に移りましょう。 そのための"CParsing" クラスを作成します。 クラスの決定:

  • クラス CArrayObj のオブジェクト-トレード配列を格納。
  • クラス CFileTxt のオブジェクト-レポートファイルを操作
  • 文字列型の変数-シンボル名を格納

初期化と初期化関数は別として、次の2つの関数がクラスに追加されます。

  • ReadFile — immediately for parsing;
  • GetSymbol —リクエスト時にシンボル名を返します。

class CParsing
  {
private:
   CArrayObj        *car_Deals;     //情報の配列
   CFileTxt         *c_File;        //ファイルを解析
   
   string            s_Symbol;      //取引のシンボル
   
public:
                     CParsing(CArrayObj *&array);
                    ~CParsing();
                    
   bool              ReadFile(string file_name);
   string            GetSymbol(void)   {  return s_Symbol;  }
  };

このクラスの関数の主な目的は、さらなる処理のトレード配列を作成することです。 作成された配列がメインプログラムで動作できるようにする必要があることを意味します。 この目的のため、トレード・配列・ストレージ用の CArrayObj クラスのオブジェクトはメイン・プログラムで宣言され、リンクは初期化時にクラスに渡されます。 このため、初期化関数は次のようになります。

CParsing::CParsing(CArrayObj *&array)  :  s_Symbol(NULL)
  {
   if(CheckPointer(array)==POINTER_INVALID)
     {
      array=new CArrayObj();
     }
   car_Deals=array;
  }

CFileTxt クラスオブジェクトの削除は初期化関数に書き込まれます。 ファイルの決済は CFile の親クラスの初期化関数で指定されますが、ここでは提供しません。

CParsing::~CParsing()
  {
   if(CheckPointer(c_File)!=POINTER_INVALID)
      delete c_File;
  }

解析に進んでみましょう。 パラメータの ReadFile 解析関数を呼び出すときに、レポートファイルの名前を指定します。 この関数で最初に行ったことは、渡されたパラメータが空でないかどうかをチェックすることです。 同様に、トレードに関する情報を保存するための配列の可用性を確認します。 少なくとも1つの条件が満たされていない場合は、関数の実行を決済し、"false" を返します。

bool CParsing::ReadFile(string file_name)
  {
   //---
   if(file_name==NULL || file_name=="" || CheckPointer(car_Deals)==POINTER_INVALID)
      return false;

次に、CFileTxt クラスオブジェクトを初期化し、関数パラメータで渡されたファイルを開きます。 エラーが発生した場合は、"false" の結果となり関数を終了します。

   if(CheckPointer(c_File)==POINTER_INVALID)
     {
      c_File=new CFileTxt();
      if(CheckPointer(c_File)==POINTER_INVALID)
         return false;
     }
   //---
   if(c_File.Open(file_name,FILE_READ|FILE_COMMON)<=0)
      return false;

ファイルを開いた後、その内容をすべて "string" 型変数に読み込みます。 ファイルが空の場合は、"false" の結果で関数を終了します。

   string html_report=NULL;
   while(!c_File.IsEnding())
      html_report+=c_File.ReadString();
   c_File.Close();
   if(html_report==NULL || html_report=="")
      return false;

次の段階では、レポートテキストでは発生しない文字を検索し、区切りシンボルとして使用することもできます。 この文字が使用できない場合は、"false" の結果で関数から終了します。

   string delimiter  =  NULL;
   ushort separate   =  0;
   for(uchar tr=1;tr<255;tr++)
     {
      string temp =  CharToString(tr);
      if(StringFind(html_report,temp,0)>0)
         continue;
      delimiter   =  temp;
      separate    =  tr;
      break;
     }
   if(delimiter==NULL)
      return false;

上記のように html ファイル構造テーブルでは、"</table>" によって閉じられています。区切りシンボルでこのタグを置き換え、その上の行で完全なレポートを分割してみましょう。 このようなやり方で、必要なテーブルを分離します。

   if(StringReplace(html_report,"</table>",delimiter)<=0)
      return false;
   //---
   s_Symbol=NULL;
   car_Deals.Clear();
   //---
   string html_tables[];
   int size=StringSplit(html_report,separate,html_tables);
   if(size<=1)
      return false;

"</tr>" でこの手順を繰り返し、テーブルを分解する。

   if(StringReplace(html_tables[size-2],"</tr>",delimiter)<=0)
      return false;
   size=StringSplit(html_tables[size-2],separate,html_tables);
   if(size<=1)
      return false;

次に、受信した文字列配列をサイクルで処理してみましょう。 まず、オーダーに関する情報を含むすべての文字列を渡します。 一方、レポート内のオーダーとトレードを分割するテキスト "Deals" で行によって整列されます。

   bool found_start=false;
   double opened_volume=0;
   for(int i=0;i<size;i++)
     {
      //---
      if(!found_start)
        {
         if(StringFind(html_tables[i],"Deals",0)>=0)
            found_start=true;
         continue;
        }

その後、各行をセルに分割し、情報をそれぞれの形式に変換します。

      string columns[];
      int temp=StringFind(html_tables[i],"<td>",0);
      if(temp<0)
         continue;
      if(temp>0)
         html_tables[i]=StringSubstr(html_tables[i],temp);
      StringReplace(html_tables[i],"<td>","");
      StringReplace(html_tables[i],"</td>",delimiter);
      temp=StringSplit(html_tables[i],separate,columns);
      if(temp<13)
         continue;
      //---
      ENUM_POSITION_TYPE   e_direction =  (ENUM_POSITION_TYPE)(columns[3]=="buy" ? POSITION_TYPE_BUY : columns[3]=="sell" ?
 POSITION_TYPE_SELL : -1);
      if(e_direction==-1)
         continue;
      //---
      datetime             dt_time     =  StringToTime(columns[0]);
      StringReplace(columns[5]," ","");
      double               d_volume    =  StringToDouble(columns[5]);
      StringReplace(columns[8]," ","");
      double               d_comission =  StringToDouble(columns[8]);
      StringReplace(columns[9]," ","");
      double               d_swap      =  StringToDouble(columns[9]);
      StringReplace(columns[10]," ","");
      double               d_profit    =  StringToDouble(columns[10]);
      if(s_Symbol==NULL || s_Symbol=="")
        {
         s_Symbol=columns[2];
         StringTrimLeft(s_Symbol);
         StringTrimRight(s_Symbol);
        }

次の段階で、トレードがポジションクローズの段階であるかどうかを確認します。 結果が正の場合は、FIFO のメソッドに基づいてポジションを決済します。

      if(opened_volume>0 && StringFind(columns[4],"out",0)>=0)
        {
         int total=car_Deals.Total();
         double total_volume=MathMin(opened_volume,d_volume);
         for(int d=0;(d<total && e_direction!=(-1) && total_volume>0);d++)
           {
            CDeal *deal=car_Deals.At(d);
            if(CheckPointer(deal)==POINTER_INVALID)
               continue;
            //---
            if(deal.Type()==e_direction)
               continue;
            //---
            double deal_unclosed=0;
            if(deal.IsClosed(deal_unclosed))
               continue;
            double close_volume     =  MathMin(deal_unclosed,total_volume);
            double close_comission  =  d_comission/d_volume*close_volume;
            double close_swap       =  d_swap/total_volume*close_volume;
            double close_profit     =  d_profit/total_volume*close_volume;
            if(deal.Close(close_volume,close_profit,close_comission,close_swap))
              {
               opened_volume  -= close_volume;
               d_volume       -= close_volume;
               total_volume   -= close_volume;
               d_comission    -= close_comission;
               d_swap         -= close_swap;
               d_profit       -= close_profit;
              }
           }
        }

次に、ポジションの開始操作が行われたかどうかを確認します。 必要に応じて、新たなトレードを行います。

      if(d_volume>0 && StringFind(columns[4],"in",0)>=0)
        {
         CDeal *deal = new CDeal(e_direction,dt_time,d_volume,d_comission);
         if(CheckPointer(deal)==POINTER_INVALID)
            return false;
         if(!car_Deals.Add(deal))
            return false;
         opened_volume  += d_volume;
        }
     }

少なくとも1つのトレードが保存された場合、関数は最後に "true"、それ以外の場合は "false" を返します。

   return (car_Deals.Total()>0);
  }

次のタスクフェーズに進みます。

4. インディケータを使用するためのクラスの準備

すでに前に言ったように、このタスクの一つは、明確に定義されたトレンドのない状態で損失のトレードをオフに選別することです。 このウェブサイト (たとえば、記事 [3] および [4]) を含む、トレンドの定義の問題が定期的に発生します。 トレンドの定義において極端な表現をするつもりはありません。 トレードシステムの分析と最適化に使用する、トレードとインジケーターの値の比較法を提案します。 よって、標準のターミナル配布パックですでに利用可能な最も広範なインジケーターを考慮してみましょう。

4.1. ATR インジケーターインクード用クラス

オシレータータイプインジケーター「真の平均値」を最初に考慮します。 周知のように、トレンド相場のボラティリティが大きくなります。 これはオシレーターの値の成長についてのシグナルになります。 どの値を保存する必要があるでしょうか? これまでのところ、EAの分析は、最後の閉じたロウソクの上にインジケーター値を保存する必要がある規定のロウソクの始値だけでなく、この値の比率を設定します。 最初の値は、現在のボラティリティが表示され、2つ目はボラティリティの変化のダイナミクスを示します。

考慮するインジケーターは、1つのバッファインジケーターのクラスの代表的なものです。 したがって、この種のインジケーターで動作するように単一のクラスを作ることは理にかなっています。

インジケーター値の保存のアプローチは、トレードの保存になります。まず、1つのトレードのインジケーター値を格納するためのクラスを作成し、外部のリクエストとデータ保存のインジケーターと即時タスクの上位レベルのクラスを作成します。

最初のクラスを「CValue」と呼んでみましょう。 インジケーターの値 (値)、インジケーターの2つの最後の値の比率 (動) と値が保存されていたオーダーチケットの数 (Deal_Ticket) に関する情報を格納するための3つのプライベート変数が含まれます。 分析時のオーダーとのインジケーター値の比較には、チケット番号が必要となります。 保存に必要なすべての値は、初期化時にクラスインスタンスに渡されます。 必要な情報を取得するためには、GetTicket、GetDinamic、ぞれの変数の値を返す関数を作成します。 さらに、インジケーターの値とそのダイナミクスを同時に返す関数 GetValues を作成します。

class CValue       : public CObject
  {
private:
   double            Value;            //インジケーターの値
   double            Dinamic;          //インジケーターの・値
   long              Deal_Ticket;      //取引のチケット
   
public:
                     CValue(double value, double dinamic, long ticket);
                    ~CValue(void);
   //---
   long              GetTicket(void)   {  return Deal_Ticket;  }
   double            GetValue(void)    {  return Value;        }
   double            GetDinamic(void)  {  return Dinamic;      }
   void              GetValues(double &value, double &dinamic);
  };

次に、上位レベルのクラスをデータ配列 COneBufferArray に格納するようにします。 "private" ブロックには、保存されたデータの配列とインジケーターハンドルが含まれます。 すべての1つのバッファのインジケーターで動作するように普遍的なクラスを作成することにしました。 しかし、異なるインジケーターの呼び出しには、パラメータのさまざまなセットが付属しています。 したがって、私の意見では、最もシンプルには、メインプログラムのインジケーターを初期化し、クラスを初期化して、必要なインジケーターのハンドルを渡すことだと思います。 後続のインジケーターの識別については、レポート内の "s_Name" 変数を使いましょう。

class COneBufferArray   :  CObject
  {
private:
   CArrayObj        *IndicatorValues;     //インジケーターの値の配列
   
   int               i_handle;            //インジケーターのハンドル
   string            s_Name;
   string            GetIndicatorName(int handle);
   
public:
                     COneBufferArray(int handle);
                    ~COneBufferArray();
   //---
   bool              SaveNewValues(long ticket);
   //---
   double            GetValue(long ticket);
   double            GetDinamic(long ticket);
   bool              GetValues(long ticket, double &value, double &dinamic);
   int               GetIndyHandle(void)  {  return i_handle;     }
   string            GetName(void)        {  return (s_Name!= NULL ? s_Name:);       }
  };

外部リクエストによってデータを保存するには、パラメータオーダーチケットを1つだけ含む SaveNewValues 関数を作成します。 この関数の先頭にデータストレージとインジケーターハンドルの配列の状態を確認します。 エラー関数の場合は、"false" の値を返します。

bool COneBufferArray::SaveNewValues(long ticket)
  {
   if(CheckPointer(IndicatorValues)==POINTER_INVALID)
      return false;
   if(i_handle==INVALID_HANDLE)
      return false;

その後、インディケーターのデータを受け取ります。 インジケーターの値がダウンロードできない場合は、false が返されます。

   double ind_buffer[];
   if(CopyBuffer(i_handle,0,1,2,ind_buffer)<2)
      return false;

次のペースで "CValue" クラスのインスタンスを作成し、必要な値を渡します。 クラスインスタンスの作成時にエラーが発生した場合、この関数は false を返します。

   CValue *object=new CValue(ind_buffer[1], (ind_buffer[0]!=0 ? ind_buffer[1]/ind_buffer[0] : 1), ticket);
   if(CheckPointer(object)==POINTER_INVALID)
      return false;

クラスがインジケータ名を取得していない場合、GetIndicatorName (関数コードは添付ファイルで提供される) で、チャートからを取得します。

   if(s_Name==NULL)
      s_Name=GetIndicatorName(i_handle);

結論として、新しく作成されたデータクラスのインスタンスを配列に追加し、返された操作の結果を関数から終了します。

   return IndicatorValues.Add(object);
  }

リクエスト時に配列からデータを返すためには、GetDinamic と GetValues を作成し、オーダーチケットで必要な値を返します。 

完全なクラスコードは添付ファイルに用意されています。

インジケーター CCI、ボリューム、フォース、チャイキンオシレーターと標準偏差によってデータを収集するためにこのクラスを適用しました。

4.2. MACD のインジケーターのクラス

コレクションにもう1つの標準インジケータ-MACD を追加してみましょう。 周知のように、これはトレンドの力と方向を決定するために使用されます。

以前のインジケーターとは対照的に、MACD は2インジケータバッファ (メインとシグナル) があります。 したがって、同様に2つの行についての情報を保存します。 データストレージのクラスコードの上に表示されるアルゴリズムを使用すると、次のようになります。

class CMACDValue      : public CObject
  {
private:
   double            Main_Value;        //メインラインの値
   double            Main_Dinamic;      //メインラインのダイナミクス
   double            Signal_Value;      //シグナル線の値
   double            Signal_Dinamic;    //シグナルライムの値
   long              Deal_Ticket;       //チケット
   
public:
                     CMACDValue(double main_value, double main_dinamic, double signal_value, double signal_dinamic, long ticket);
                    ~CMACDValue(void);
   //---
   long              GetTicket(void)         {  return Deal_Ticket;     }
   double            GetMainValue(void)      {  return Main_Value;      }
   double            GetMainDinamic(void)    {  return Main_Dinamic;    }
   double            GetSignalValue(void)    {  return Signal_Value;    }
   double            GetSignalDinamic(void)  {  return Signal_Dinamic;  }
   void              GetValues(double &main_value, double &main_dinamic, double &signal_value, double &signal_dinamic);
  };

それぞれの変更は、データ配列を使用するためのクラスでも行われます。 セクション4.1 で説明されているユニバーサルクラスとは対照的に、このクラスは特定のインジケーターで動作するため、クラスの初期化時には、渡されるインジケーターハンドルではなく、初期化に必要なパラメータを指定します。 インジケーターの初期化は、クラス内で直ちに実行されます。

class CMACD
  {
private:
   CArrayObj        *IndicatorValues;     //インジケーターの値の配列
   
   int               i_handle;            //インジケーターのハンドル
   
public:
                     CMACD(string symbol, ENUM_TIMEFRAMES timeframe, uint fast_ema, uint slow_ema, uint signal, ENUM_APPLIED_PRICE applied_price);
                    ~CMACD();
   //---
   bool              SaveNewValues(long ticket);
   //---
   double            GetMainValue(long ticket);
   double            GetMainDinamic(long ticket);
   double            GetSignalValue(long ticket);
   double            GetSignalDinamic(long ticket);
   bool              GetValues(long ticket, double &main_value, double &main_dinamic, double &signal_value, double &signal_dinamic);                
  };

この関数の全体のロジックは同じままで、変更はインジケーターバッファと保存された変数の量のみを考慮します。

bool CMACD::SaveNewValues(long ticket)
  {
   if(CheckPointer(IndicatorValues)==POINTER_INVALID)
      return false;
   if(i_handle==INVALID_HANDLE)
      return false;
   double main[], signal[];
   if(!CopyBuffer(i_handle,0,1,2,main)<2 || !CopyBuffer(i_handle,1,1,2,signal)<2)
      return false;
   CMACDValue *object=new CMACDValue(main[1], (main[0]!=0 ? main[1]/main[0] : 1), signal[1], (signal[0]!=0 ? signal[1]/signal[0] : 1), ticket);
   if(CheckPointer(object)==POINTER_INVALID)
      return false;
   return IndicatorValues.Add(object);
  }

スケーリングの同様のロジックは、インジケーターバッファの任意の量に適用できます。 選択したインジケーターバッファのみを保存する場合は、しれぞれのクラスの SaveNewValues 関数で記述するだけで十分です。 しかし、今の段階ではまだ利益のあるトレードと特定のインジケーターのバッファの値との間の相互関係があるかどうかはわからないが、存在する場合、これを行うことをお勧めしません。

マテリアルを統合するためには、3データバッファとインジケーターデータを保存する別の例をレンダリングすることができます。

4.3. ADX インジケーターを含めるためのクラス

ADX インジケーターは、トレンドの力と方向を決定するために広く使用されています。 "マネーボックス" に追加されます。

このインジケーターには3つのインジケーターバッファがあり、上記の推奨スケーリングメソッドに従って、保存された変数の数を増やします。 したがって、データストレージクラスは次のようになります。

class CADXValue      : public CObject
  {
private:
   double            ADX_Value;        //ADX 値
   double            ADX_Dinamic;      //ADX の・値
   double            PDI_Value;        //+ DI 値
   double            PDI_Dinamic;      //+ DIの値
   double            NDI_Value;        //-DIの値
   double            NDI_Dinamic;      //-DIのダイナミクス
   long              Deal_Ticket;      //取引のチケット
   
public:
                     CADXValue(double adx_value, double adx_dinamic, double pdi_value, double pdi_dinamic, double ndi_value, double ndi_dinamic, long ticket);
                    ~CADXValue(void);
   //---
   long              GetTicket(void)         {  return Deal_Ticket;     }
   double            GetADXValue(void)       {  return ADX_Value;       }
   double            GetADXDinamic(void)     {  return ADX_Dinamic;     }
   double            GetPDIValue(void)       {  return PDI_Value;       }
   double            GetPDIDinamic(void)     {  return PDI_Dinamic;     }
   double            GetNDIValue(void)       {  return NDI_Value;       }
   double            GetNDIDinamic(void)     {  return NDI_Dinamic;     }
   void              GetValues(double &adx_value, double &adx_dinamic, double &pdi_value, double &pdi_dinamic, double &ndi_value, double &ndi_dinamic);
  };

 格納されるデータの増加がある場合、配列を使用するクラスの変更を伴うことになります。

class CADX
  {
private:
   CArrayObj        *IndicatorValues;     //インジケーターの値の配列
   
   int               i_handle;            //インジケーターのハンドル
   
public:
                     CADX(string symbol, ENUM_TIMEFRAMES timeframe, uint period);
                    ~CADX();
   //---
   bool              SaveNewValues(long ticket);
   //---
   double            GetADXValue(long ticket);
   double            GetADXDinamic(long ticket);
   double            GetPDIValue(long ticket);
   double            GetPDIDinamic(long ticket);
   double            GetNDIValue(long ticket);
   double            GetNDIDinamic(long ticket);
   bool              GetValues(long ticket,double &adx_value,double &adx_dinamic,double &pdi_value,double &pdi_dinamic,double &ndi_value,double &ndi_dinamic);
  };
bool CADX::SaveNewValues(long ticket)
  {
   if(CheckPointer(IndicatorValues)==POINTER_INVALID)
      return false;
   if(i_handle==INVALID_HANDLE)
      return false;
   double adx[], pdi[], ndi[];
   if(!CopyBuffer(i_handle,0,1,2,adx)<2 || !CopyBuffer(i_handle,1,1,2,pdi)<2 || !CopyBuffer(i_handle,1,1,2,ndi)<2)
      return false;
   CADXValue *object=new CADXValue(adx[1], (adx[0]!=0 ? adx [1]/adx [0]: 1)、pdi [1]、(pdi [0]! =0 ? pdi [1]/pdi [0]: 1), .ndi [1], (.ndi [0]! =0 ? ndi[1]/ndi[0] : 1), ticket);
   if(CheckPointer(object)==POINTER_INVALID)
      return false;
   return IndicatorValues.Add(object);
  }

インジケーターとタスクのクラスを構築する原則を理解しているものと思います。 したがって、記事をいたずらに長くしないようにするため、次のインジケーターのコードを記述しません。 同様に、分析の "マネーボックス" に BW MFI とアリゲーターを追加しました。 添付ファイルで完全なコードを得ることができます。

5. 結果出力用のレポートフォームの準備

トレードの瞬間に関係するインジケーターから情報を取得した後、得られたデータの分析について考える必要があります。 私の意見では、最も明確にぞれのインジケーターの値にトレード利益の依存関係のチャートを構築することです。 記事 [2] のVictor によって提案された技術に応じてチャートを構築します。

これまでのことから、インジケーターの値に利益の依存関係を検索するトレードの最適化を実装します。 トレードを繰り返す場合は、トレード数とインジケーター値の間の依存関係を検索する必要があります。

まず、各インジケーターの情報を準備するクラスを作成します。

5.1. ユニバーサルクラスの1つのバッファインジケータ

1つのバッファインジケータを使用するクラスが最初に作成されます。 どの情報を分析することができるでしょうか。 インジケーターバッファの値とその変化のダイナミクスを保存したことに注意してください。 したがって、分析することができます。

  • ポジション開始時のインジケーター値に対する実行操作からの利益の依存性
  • インジケーターラインのトレンドが利益に与える影響
  • 同様に、インジケーター値の複雑な影響と実行操作の結果にそのダイナミクス。

チャート描画の場合は、クラス CStaticOneBuffer を作成します。 このクラスには、保存されたデータ配列 DataArray への参照、プリセットステップ d_Step による値のインジケーター値の配列、およびロングおよびショートポジションの合計利益の2つの配列が含まれます。 注意: 総利益計算の配列は2次元になります。 最初の測定値の大きさは、Value 配列のサイズに対応します。 2番目の測定は3つの要素が含まれます。1つ目-落下インジケータダイナミクス、2番目-水平方向のインジケータの動き、3番目-成長運動。

クラスの初期化時には、パラメータでデータ配列への参照と、インジケーター値のステップサイズを設定します。

class CStaticOneBuffer  :  CObject
  {
private:
   COneBufferArray  *DataArray;
   
   double            d_Step;                    //値配列のステップ
   double            Value[];                   //値の配列
   double            Long_Profit[][3];          //買いトレードの利益の配列、direct -> DOWN-0, EQUAL-1, UP-22
   double            Short_Profit[][3];         //売りトレード利益の配列、direct -> DOWN-0, EQUAL-1, UP-2
   
   bool              AdValues(double value, double dinamic, double profit, ENUM_POSITION_TYPE type);
   int               GetIndex(double value);
   bool              Sort(void);
   
public:
                     CStaticOneBuffer(COneBufferArray *data, double step);
                    ~CStaticOneBuffer();
   bool              Ad(long ticket, double profit, ENUM_POSITION_TYPE type);
   string            HTML_header(void);
   string            HTML_body(void);
  };

初期化関数では、渡された値を保存し、使用されている配列をゼロにします。

CStaticOneBuffer::CStaticOneBuffer(COneBufferArray *data,double step)
  {
   DataArray   =  data;
   d_Step      =  step;
   ArrayFree(Value);
   ArrayFree(Long_Profit);
   ArrayFree(Short_Profit);
  }

統計情報を収集するためには、トレードについての情報を渡すAd関数を作成します。 それぞれのインディケータパラメータは関数の内部にあり、データは必要な配列要素に保存されます。

bool CStaticOneBuffer::Ad(long ticket,double profit,ENUM_POSITION_TYPE type)
  {
   if(CheckPointer(DataArray)==POINTER_INVALID)
      return false;

   double value, dinamic;
   if(!DataArray.GetValues(ticket,value,dinamic))
      return false;
   value = NormalizeDouble(value/d_Step,0)*d_Step;
   return AdValues(value,dinamic,profit,type);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CStaticOneBuffer::AdValues(double value,double dinamic,double profit,ENUM_POSITION_TYPE type)
  {
   int index=GetIndex(value);
   if(index<0)
      return false;
   
   switch(type)
     {
      case POSITION_TYPE_BUY:
        if(dinamic<1)
           Long_Profit[index,0]+=profit;
        else
           if(dinamic==1)
              Long_Profit[index,1]+=profit;
           else
              Long_Profit[index,2]+=profit;
        break;
      case POSITION_TYPE_SELL:
        if(dinamic<1)
           Short_Profit[index,0]+=profit;
        else
           if(dinamic==1)
              Short_Profit[index,1]+=profit;
           else
              Short_Profit[index,2]+=profit;
        break;
     }
   return true;
  }

チャートの視覚化で、HTML ページのヘッダーと本文のコードの断片が生成される HTML_header と HTML_body を作成します。 HTML ページコードの構築の原則は記事 [2] で詳しく説明されていますが、焦点は当てません。 完全なコードは添付ファイルに用意されています。

5.2. ビルウィリアムズ MFI のインジケーターのデータを表示するためのクラス

次にビルウィリアムズ MFI のインジケーターを検討してみましょう。 チャートに表示するメソッドでは、1つのバッファのインジケーターに似ていますが、BW MFIは、値を持つカラーパレットのバッファもあります。 同時に、2つのバッファインジケータとは対照的に、カラーバッファの変化のダイナミクスに興味がありません。 したがって、1つのバッファのインジケーターの上に提案されたチャートには、インジケーターの色だけでなく、現在のインジケータの色に応じて、値とインジケーターのダイナミクスの複雑な影響のチャートに利益依存のチャートが追加されます。

統計データを収集し、分析チャートを作成するために、クラス CStaticBWMFI を作成します。 クラス構造は、上で考えられるものと類推されます。 変更の利益計算の配列は、今では3つの次元があります。 第3次元は使用される色の数に従って4つの要素を得た。

class CStaticBWMFI  :  CObject
  {
private:
   CBWMFI           *DataArray;
   
   double            d_Step;                       //値配列のステップ
   double            Value[];                      //値の配列
   double            Long_Profit[][3][4];          //買いトレードの利益の配列、direct -> DOWN-0, EQUAL-1, UP-2
   double            Short_Profit[][3][4];         //売りトレード利益の配列、direct -> DOWN-0, EQUAL-1, UP-2
   
   bool              AdValues(double value, double _color, double dinamic, double profit, ENUM_POSITION_TYPE type);
   int               GetIndex(double value);
   bool              Sort(void);
   
public:
                     CStaticBWMFI(CBWMFI *data, double step);
                    ~CStaticBWMFI();
   bool              Ad(long ticket, double profit, ENUM_POSITION_TYPE type);
   string            HTML_header(void);
   string            HTML_body(void);
  };

完全なコードは添付ファイルに用意されています。

5.3. MACD インジケーターのデータを表示するためのクラス

さらに、MACD のインジケーターを考えてみましょう。 ご存知のように、2つのバッファ: ヒストグラムとシグナル線があります。 このインジケーターシグナルの解釈のルールの下で、ヒストグラムの価値および動きの方向はシグナル線のポジションと同様、重要です(上かヒストグラムの下)。 包括的な分析に、チャートの数を作成します。

  • ヒストグラムとその方向の値に対するトレード利益率の依存性。
  • シグナル線とその方向の値に対するトレード利益率の依存性
  • ヒストグラムに対するシグナル線ポジションに対する利益の依存性
  • ヒストグラムの値の共同効果に対する利益の依存性, ヒストグラムに対する方向とシグナル線のポジション.
データ分析では、CStaticMACD クラスを作成します。 クラスを構築する際には、以前の統計クラスを構築するときと同じ原則が適用されます。 ヒストグラム値によって利益統計の3次元配列を持つことになりますが、前のクラスとは対照的に、3番目の次元は、ヒストグラム (低いレベルで、より高い) に関してシグナル線のポジションに応じて3つの要素が含まれます。 同様に、シグナル線の値によって利益の計算の別の2次元配列を追加します。

class CStaticMACD  :  CObject
  {
private:
   CMACD            *DataArray;
   
   double            d_Step;                       //値配列のステップ
   double            Value[];                      //値の配列
   double            SignalValue[];                //値の配列
   double            Long_Profit[][3][3];          //買いトレードの利益の配列、direct -> DOWN-0, EQUAL-1, UP-2
   double            Short_Profit[][3][3];         //売りトレード利益の配列、direct -> DOWN-0, EQUAL-1, UP-2
   double            Signal_Long_Profit[][3];      //買いトレードの利益の配列、direct -> DOWN-0, EQUAL-1, UP-2
   double            Signal_Short_Profit[][3];     //売りトレード利益の配列、direct -> DOWN-0, EQUAL-1, UP-2
   
   bool              AdValues(double main_value, double main_dinamic, double signal_value, double signal_dinamic, double profit, ENUM_POSITION_TYPE type);
   int               GetIndex(double value);
   int               GetSignalIndex(double value);
   bool              Sort(void);
   
public:
                     CStaticMACD(CMACD *data, double step);
                    ~CStaticMACD();
   bool              Ad(long ticket, double profit, ENUM_POSITION_TYPE type);
   string            HTML_header(void);
   string            HTML_body(void);
  };

ご覧の通り、クラスの構造、名前と関数の指定は同じままでした。 変更については、添付ファイルで得ることができる関数の内容のみを懸念しています。

5.4. ADX インジケーターのデータを表示するためのクラス

次の1つを検討する CStaticADX クラスです。 ADX インジケーターの値によって統計情報を収集します。 インジケーターシグナルの解釈のルール: ライン + di は正の力、-di-負の力、および ADX-はミドルの力を示しています。 ルールから、依存関係のチャートを作成します。

  • +DI値に対する利益の依存性、ADXに対する方向と位置
  • 利益の-DI値の依存性、その方向性と ADX に対する位置。

統計情報のクラスのデータをもう少し収集することにしました。 必要な結果:

  • インジケーター値;
  • 線の方向;
  • 反対の移動ラインに関する位置;
  • 反対の移動ラインの方向;
  • ADX 行に対する位置
  • ADXの方向。
このような情報の断片化と、以前のクラスで使用されるアプローチでは、6次元配列を必要としました。 しかし、このようなサイズの配列は MQL ではサポートされていません。 このタスクを解決するために、補助クラス CProfitData が作成され、必要な情報がすべて保存されます。

class CProfitData
  {
   public:
   double         Value;
   double         LongProfit[3]/*UppositePosition*/[3]/*Upposite Direct*/[3]/*ADX position*/[3]/*ADX direct*/;
   double         ShortProfit[3]/*UppositePosition*/[3]/*Upposite Direct*/[3]/*ADX position*/[3]/*ADX direct*/;
   
                  CProfitData(void) 
                   ArrayInitialize(LongProfit,0);ArrayInitialize(ShortProfit,0); }
                 ~CProfitData(void) {};
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CStaticADX  :  CObject
  {
private:
   CADX             *DataArray;
   
   double            d_Step;           //値配列のステップ
   CProfitData      *PDI[][3];         //値の配列 + DI
   CProfitData      *NDI[][3];         //値の配列-DI
   
   bool              AdValues(double adx_value, double adx_dinamic, double pdi_value, double pdi_dinamic, double ndi_value, double ndi_dinamic, double profit, ENUM_POSITION_TYPE type);
   int               GetPDIIndex(double value);
   int               GetNDIIndex(double value);
   bool              Sort(void);
   
public:
                     CStaticADX(CADX *data, double step);
                    ~CStaticADX();
   bool              Ad(long ticket, double profit, ENUM_POSITION_TYPE type);
   string            HTML_header(void);
   string            HTML_body(void);
  };

他の点では前のクラスからのアプローチとして原理原則は維持されました。 完全なコードは添付ファイルに用意されています。

5.5. アリゲーターインジケーターのデータを表示するためのクラス

このブロックの最後にアリゲーターのインジケーターのデータを収集するクラスを作成してみましょう. このインジケータのシグナルは、異なる期間の3つの移動平均に基づいています。 したがって、インジケーターを解釈するときにインジケーターラインの特定の値は重要ではありません。 はるかに重要なのは、線の方向とポジションです。

インジケーターシグナルをより具体的にするために、ラインのポジションによってトレンドを決定しましょう。 LIPのラインが、TEETHよりも高い場合、TEETHはJAWよりも高く、トレンドとして買いを検討してください。 LIPがTEETHよりも低い場合は、TEETHがJAWよりも低いので-売りを検討してください。 ラインの順番がない場合にはフラットだとみなします。

それぞれ、チャートはトレンド方向のシグナルとインジケータラインのダイナミクスから構築されます。

上記の指定されたエントリーデータに続いて CStaticAlligator クラスを作成します。 クラスの原則は、以前のクラスから取得されます。

class CStaticAlligator  :  CObject
  {
private:
   CAlligator             *DataArray;
   
   double            Long_Profit[3]/*Signal*/[3]/*JAW direct*/[3]/*TEETH direct*/[3]/*LIPS direct*/;  //長期トレード利益の配列
   double            Short_Profit[3]/*Signal*/[3]/*JAW direct*/[3]/*TEETH direct*/[3]/*LIPS direct*/; //Array of short feals profit
   
   bool              AdValues(double jaw_value, double jaw_dinamic, double teeth_value, double teeth_dinamic, double lips_value, double lips_dinamic, double profit, ENUM_POSITION_TYPE type);
   
public:
                     CStaticAlligator(CAlligator *data);
                    ~CStaticAlligator();
   bool              Ad(long ticket, double profit, ENUM_POSITION_TYPE type);
   string            HTML_header(void);
   string            HTML_body(void);
  };

完全なコードは添付ファイルに用意されています。

6. 情報の収集と分析の EA の構築

すべての準備タスクが完了したら、分析データの情報収集と出力のストラテジーテスターでEA を作成してみましょう。 まず第一に、EA のインプットパラメータでは、分析のテストレポートファイルの名前を指定し、使用される時間枠と使用されるインジケーターのすべての必要なパラメータを用意します。

input string            FileName          =  "Kalman_test.html"   ;
input ENUM_TIMEFRAMES   Timefarame        =  PERIOD_CURRENT       ;
input string            s1                =  "ADX"                ;  //---
input uint              ADX_Period        =  14                   ;
input string            s2                =  "Alligator"          ;  //---
input uint              JAW_Period        =  13                   ;
input uint              JAW_Shift         =  8                    ;
input uint              TEETH_Period      =  8                    ;
input uint              TEETH_Shift       =  5                    ;
input uint              LIPS_Period       =  5                    ;
input uint              LIPS_Shift        =  3                    ;
input ENUM_MA_METHOD    Alligator_Method  =  MODE_SMMA            ;
input ENUM_APPLIED_PRICE Alligator_Price  =  PRICE_MEDIAN         ;
input string            s3                =  "ATR"                ;  //---
input uint              ATR_Period        =  14                   ;
input string            s4                =  "BW MFI"             ;  //---
input ENUM_APPLIED_VOLUME BWMFI_Volume    =  VOLUME_TICK          ;
input string            s5                =  "CCI"                ;  //---
input uint              CCI_Period        =  14                   ;
input ENUM_APPLIED_PRICE CCI_Price        =  PRICE_TYPICAL        ;
input string            s6                =  "Chaikin"            ;  //---
input uint              Ch_Fast_Period    =  3                    ;
input uint              Ch_Slow_Period    =  14                   ;
input ENUM_MA_METHOD    Ch_Method         =  MODE_EMA             ;
input ENUM_APPLIED_VOLUME Ch_Volume       =  VOLUME_TICK          ;
input string            s7                =  "Force Index"        ;  //---
input uint              Force_Period      =  14                   ;
input ENUM_MA_METHOD    Force_Method      =  MODE_SMA             ;
input ENUM_APPLIED_VOLUME Force_Volume    =  VOLUME_TICK          ;
input string            s8                =  "MACD"               ;  //---
input uint              MACD_Fast         =  12                   ;
input uint              MACD_Slow         =  26                   ;
input uint              MACD_Signal       =  9                    ;
input ENUM_APPLIED_PRICE MACD_Price       =  PRICE_CLOSE          ;
input string            s9                =  "Standart Deviation" ;  //---
input uint              StdDev_Period     =  14                   ;
input uint              StdDev_Shift      =  0                    ;
input ENUM_MA_METHOD    StdDev_Method     =  MODE_SMA             ;
input ENUM_APPLIED_PRICE StdDev_Price     =  PRICE_CLOSE          ;
input string            s10               =  "Volumes"            ;  //---
input ENUM_APPLIED_VOLUME Applied_Volume  =  VOLUME_TICK          ;

次に、上記で説明したすべてのクラスのインスタンスを宣言します。

CArrayObj         *Deals;
CADX              *ADX;
CAlligator        *Alligator;
COneBufferArray   *ATR;
CBWMFI            *BWMFI;
COneBufferArray   *CCI;
COneBufferArray   *Chaikin;
COneBufferArray   *Force;
CMACD             *MACD;
COneBufferArray   *StdDev;
COneBufferArray   *Volume;
CStaticOneBuffer  *IndicatorsStatic[];
CStaticBWMFI      *BWMFI_Stat;
CStaticMACD       *MACD_Stat;
CStaticADX        *ADX_Stat;
CStaticAlligator  *Alligator_Stat;

6.1. EA 初期化関数

これまでのところ、 EA はストラテジーテスターのデータ分析に指定されているように、まず開始されている環境を確認してください。 テスターで始める場合は、その初期化を中止する必要があります。

int()
  {
//---
   if(!MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_OPTIMIZATION))
      return INIT_FAILED;

次に、レポートファイルのテストからデータの解析を行います。 レポートからのデータ読み出し後、解析クラスインスタンスは必要ではなくなるので、メモリから削除します。

   CParsing *Parsing =  new CParsing(Deals);
   if(CheckPointer(Parsing)==POINTER_INVALID)
      return INIT_FAILED;
   if(!Parsing.ReadFile(FileName) || CheckPointer(Deals)==POINTER_INVALID || Deals.Total()<=0)
     {
      delete Parsing;
      return INIT_FAILED;
     }
   delete Parsing;

その後、インジケータークラスの初期化を実行します。

//---
   ADX =  new CADX(_Symbol,Timefarame,ADX_Period);
   if(CheckPointer(ADX)==POINTER_INVALID)
      return INIT_FAILED;
//---
   Alligator =  new CAlligator(_Symbol,Timefarame,JAW_Period,JAW_Shift,TEETH_Period,TEETH_Shift,LIPS_Period,LIPS_Shift,Alligator_Method,Alligator_Price);
   if(CheckPointer(Alligator)==POINTER_INVALID)
      return INIT_FAILED;
//---
   int handle=iATR(_Symbol,Timefarame,ATR_Period);
   if(handle>0)
     {
      ATR      =  new COneBufferArray(handle);
      if(CheckPointer(ATR)==POINTER_INVALID)
         return INIT_FAILED;
     }
//---
   BWMFI    =  new CBWMFI(_Symbol,Timefarame,BWMFI_Volume);
   if(CheckPointer(BWMFI)==POINTER_INVALID)
      return INIT_FAILED;
//---
   handle=iCCI(_Symbol,Timefarame,CCI_Period,CCI_Price);
   if(handle>0)
     {
      CCI      =  new COneBufferArray(handle);
      if(CheckPointer(CCI)==POINTER_INVALID)
         return INIT_FAILED;
     }
//---
   handle=iChaikin(_Symbol,Timefarame,Ch_Fast_Period,Ch_Slow_Period,Ch_Method,Ch_Volume);
   if(handle>0)
     {
      Chaikin  =  new COneBufferArray(handle);
      if(CheckPointer(Chaikin)==POINTER_INVALID)
         return INIT_FAILED;
     }
//---
   handle=iForce(_Symbol,Timefarame,Force_Period,Force_Method,Force_Volume);
   if(handle>0)
     {
      Force    =  new COneBufferArray(handle);
      if(CheckPointer(Force)==POINTER_INVALID)
         return INIT_FAILED;
     }
//---
   MACD     =  new CMACD(_Symbol,Timefarame,MACD_Fast,MACD_Slow,MACD_Signal,MACD_Price);
   if(CheckPointer(MACD)==POINTER_INVALID)
      return INIT_FAILED;
//---
   handle=iStdDev(_Symbol,Timefarame,StdDev_Period,StdDev_Shift,StdDev_Method,StdDev_Price);
   if(handle>0)
     {
      StdDev   =  new COneBufferArray(handle);
      if(CheckPointer(StdDev)==POINTER_INVALID)
         return INIT_FAILED;
     }
//---
   handle=iVolumes(_Symbol,Timefarame,Applied_Volume);
   if(handle>0)
     {
      Volume   =  new COneBufferArray(handle);
      if(CheckPointer(Volume)==POINTER_INVALID)
         return INIT_FAILED;
     }

関数を終了するには、関数を0に設定してから閉じます。

   cur_ticket   =  0;
//---
   return(INIT_SUCCEEDED);
  }

6.2. 統計データの収集

インジケーター状態に関するデータの収集は、OnTick 関数で実行されます。 この関数の先頭に、すべてのオーダーの情報が収集されるかどうかを確認します。 yes の場合は、関数を決済します。

void OnTick()
  {
   if(cur_ticket>=Deals.Total())
      return;

次のステップで分析されるトレードの性能の時間は処理したときと比べられます。 トレードの時間でない場合は、関数を終了します。

   CDeal *object  =  Deals.At(cur_ticket);
   if(object.GetTime()>TimeCurrent())
      return;

前のチェックアップをする場合は、インジケータークラスのインスタンスの状態を確認し、各インジケータークラスに必要な情報を呼び出し SaveNewValues 関数を保存します。

   if(CheckPointer(ADX)!=POINTER_INVALID)
      ADX.SaveNewValues(cur_ticket);
   //---
   if(CheckPointer(Alligator)!=POINTER_INVALID)
      Alligator.SaveNewValues(cur_ticket);
   //---
   if(CheckPointer(ATR)!=POINTER_INVALID)
      ATR.SaveNewValues(cur_ticket);
   //---
   if(CheckPointer(BWMFI)!=POINTER_INVALID)
      BWMFI.SaveNewValues(cur_ticket);
   //---
   if(CheckPointer(CCI)!=POINTER_INVALID)
      CCI.SaveNewValues(cur_ticket);
   //---
   if(CheckPointer(Chaikin)!=POINTER_INVALID)
      Chaikin.SaveNewValues(cur_ticket);
   //---
   if(CheckPointer(Force)!=POINTER_INVALID)
      Force.SaveNewValues(cur_ticket);
   //---
   if(CheckPointer(MACD)!=POINTER_INVALID)
      MACD.SaveNewValues(cur_ticket);
   //---
   if(CheckPointer(StdDev)!=POINTER_INVALID)
      StdDev.SaveNewValues(cur_ticket);
   //---
   if(CheckPointer(Volume)!=POINTER_INVALID)
      Volume.SaveNewValues(cur_ticket);

この関数の終わりには、処理された命令のカウンタを増加し、終了します。

   cur_ticket++;
   return;
  }

6.3. 分析のチャート出力

データ分析およびレポート出力は、OnTester 関数で実装されます。 この関数を起動すると、分析トレードの数量を確認します。

double OnTester()
  {
   double ret=0.0;
   int total=Deals.Total();

分析を実施する必要がある場合は、統計クラスの初期化を実行します。

その後の処理を容易にするために、1バッファインジケーターの統計クラスを配列に収集します。 したがって、初期化カウントと並行して1つのバッファインジケータが使用されます。

   int total_indy=0;
   if(total>0)
     {
      if(CheckPointer(ADX)!=POINTER_INVALID)
         ADX_Stat=new CStaticADX(ADX,1);
      //---
      if(CheckPointer(Alligator)!=POINTER_INVALID)
         Alligator_Stat=new CStaticAlligator(Alligator);
      //---
      if(CheckPointer(ATR)!=POINTER_INVALID)
        {
         CStaticOneBuffer *indy=new CStaticOneBuffer(ATR,_Point*10);
         if(CheckPointer(indy)!=POINTER_INVALID)
           {
            if(ArrayResize(IndicatorsStatic,total_indy+1)>0)
              {
               IndicatorsStatic[total_indy]=indy;
               total_indy++;
              }
           }
        }
      //---
      if(CheckPointer(BWMFI)!=POINTER_INVALID)
         BWMFI_Stat=new CStaticBWMFI(BWMFI,_Point*100);
      //---
      if(CheckPointer(CCI)!=POINTER_INVALID)
        {
         CStaticOneBuffer *indy=new CStaticOneBuffer(CCI,10);
         if(CheckPointer(indy)!=POINTER_INVALID)
            if(ArrayResize(IndicatorsStatic,total_indy+1)>0)
              {
               IndicatorsStatic[total_indy]=indy;
               total_indy++;
              }
        }
      //---
      if(CheckPointer(Chaikin)!=POINTER_INVALID)
        {
         CStaticOneBuffer *indy=new CStaticOneBuffer(Chaikin,100);
         if(CheckPointer(indy)!=POINTER_INVALID)
            if(ArrayResize(IndicatorsStatic,total_indy+1)>0)
              {
               IndicatorsStatic[total_indy]=indy;
               total_indy++;
              }
        }
      //---
      if(CheckPointer(Force)!=POINTER_INVALID)
        {
         CStaticOneBuffer *indy=new CStaticOneBuffer(Force,0.1);
         if(CheckPointer(indy)!=POINTER_INVALID)
            if(ArrayResize(IndicatorsStatic,total_indy+1)>0)
              {
               IndicatorsStatic[total_indy]=indy;
               total_indy++;
              }
        }
      //---
      if(CheckPointer(MACD)!=POINTER_INVALID)
         MACD_Stat=new CStaticMACD(MACD,_Point*10);
      //---
      if(CheckPointer(StdDev)!=POINTER_INVALID)
        {
         CStaticOneBuffer *indy=new CStaticOneBuffer(StdDev,_Point*10);
         if(CheckPointer(indy)!=POINTER_INVALID)
            if(ArrayResize(IndicatorsStatic,total_indy+1)>0)
              {
               IndicatorsStatic[total_indy]=indy;
               total_indy++;
              }
        }
      //---
      if(CheckPointer(Volume)!=POINTER_INVALID)
        {
         CStaticOneBuffer *indy=new CStaticOneBuffer(Volume,100);
         if(CheckPointer(indy)!=POINTER_INVALID)
            if(ArrayResize(IndicatorsStatic,total_indy+1)>0)
              {
               IndicatorsStatic[total_indy]=indy;
               total_indy++;
              }
        }
     }

さらに、インジケーターデータをそれぞれのトレードと比較し、グラフィックレポートの出力に必要な指示によって情報をグループ化します。 各統計クラスの呼び出しのAd関数で、そのパラメータのトレードについての情報を渡しました。

   for(int i=0;i<total;i++)
     {
      CDeal               *deal     =  Deals.At(i);
      ENUM_POSITION_TYPE   type     =  deal.Type();
      double               d_profit =  deal.GetProfit();
      
      for(int ind=0;ind<total_indy;ind++)
         IndicatorsStatic[ind].Ad(i,d_profit,type);
      if(CheckPointer(BWMFI_Stat)!=POINTER_INVALID)
         BWMFI_Stat.Ad(i,d_profit,type);
      if(CheckPointer(MACD_Stat)!=POINTER_INVALID)
         MACD_Stat.Ad(i,d_profit,type);
      if(CheckPointer(ADX_Stat)!=POINTER_INVALID)
         ADX_Stat.Ad(i,d_profit,type);
      if(CheckPointer(Alligator_Stat)!=POINTER_INVALID)
         Alligator_Stat.Ad(i,d_profit,type);
     }

データのグループ化後、レポートファイルレポートを作成します。 Report.htmlをターミナルの共有フォルダに保存します。

   if(total_indy>0 || CheckPointer(BWMFI_Stat)!=POINTER_INVALID || CheckPointer(MACD_Stat)!=POINTER_INVALID
      || CheckPointer(ADX_Stat)!=POINTER_INVALID || CheckPointer(Alligator_Stat)!=POINTER_INVALID )
     {
      int handle=FileOpen("Report.html",FILE_WRITE|FILE_TXT|FILE_COMMON);
      if(handle<0)
         return ret;

ファイルの先頭に html レポートのヘッダーを書く。

      FileWrite(handle,"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">");
      FileWrite(handle,"<html> <head> <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">");
      FileWrite(handle,"<title>Deals to Indicators</title> <!-- - -->");
      FileWrite(handle,"<script src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.js\" type=\"text/javascript\"></script>");
      FileWrite(handle,"<script src=\"https://code.highcharts.com/highcharts.js\" type=\"text/javascript\"></script>");
      FileWrite(handle,"<!-- - --> <script type=\"text/javascript\">$(document).ready(function(){");

次に、すべての統計クラスの HTML_header 関数を1つずつ呼び出して、チャート描画用のファイルデータを入力します。

      for(int ind=0;ind<total_indy;ind++)
         FileWrite(handle,IndicatorsStatic[ind].HTML_header());
      if(CheckPointer(BWMFI_Stat)!=POINTER_INVALID)
         FileWrite(handle,BWMFI_Stat.HTML_header());
      if(CheckPointer(MACD_Stat)!=POINTER_INVALID)
         FileWrite(handle,MACD_Stat.HTML_header());
      if(CheckPointer(ADX_Stat)!=POINTER_INVALID)
         FileWrite(handle,ADX_Stat.HTML_header());
      if(CheckPointer(Alligator_Stat)!=POINTER_INVALID)
         FileWrite(handle,Alligator_Stat.HTML_header());

その後、各統計クラスの HTML_body 関数を1つずつ呼び出して、レポート出力用のテンプレートを作成します。 注: この関数の呼び出しによって、統計クラスでタスクを終了し、メモリをクリアするため削除します。

      FileWrite(handle,"});</script> <!-- - --> </head> <body>");
      for(int ind=0;ind<total_indy;ind++)
        {
         FileWrite(handle,IndicatorsStatic[ind].HTML_body());
         delete IndicatorsStatic[ind];
        }
      if(CheckPointer(BWMFI_Stat)!=POINTER_INVALID)
        {
         FileWrite(handle,BWMFI_Stat.HTML_body());
         delete BWMFI_Stat;
        }
      if(CheckPointer(MACD_Stat)!=POINTER_INVALID)
        {
         FileWrite(handle,MACD_Stat.HTML_body());
         delete MACD_Stat;
        }
      if(CheckPointer(ADX_Stat)!=POINTER_INVALID)
        {
         FileWrite(handle,ADX_Stat.HTML_body());
         delete ADX_Stat;
        }
      if(CheckPointer(Alligator_Stat)!=POINTER_INVALID)
        {
         FileWrite(handle,Alligator_Stat.HTML_body());
         delete Alligator_Stat;
        }

最後に、終了タグの書き込みを完了し、ファイルを閉じて、配列をクリアし、関数から終了します。

      FileWrite(handle,"</body> </html>");
      FileFlush(handle);
      FileClose(handle);
     }
//---
   ArrayFree(IndicatorsStatic);
//---
   return(ret);
  }

OnDeinit 関数の残りのクラスを削除することを忘れないでください。

7. 情報分析

今回のタスクは論理的な帰結に近づいています。 今での結果を見てみる必要があります。 ストラテジーテスターにこれを行うため、記事の2番目のセクションで使ったEAをテストし、新たに作成された分析EA のテストを開始し、すべての設定を繰り返します。

テストが完了したら、共有ターミナルフォルダを開き、レポートを見つけます。 ブラウザで開きます。 さらに、レポートから例を提供します。

7.1. ATR

ATR レポート

ATR インジケーターにおける利益依存度チャートを分析するとき、潜在的に収益性の高い領域を見ることができず、トレードのフィルターの可能性はありません。

7.2. CCI

CCI レポート

CCI インジケーターにおける利益依存のチャートは、200より高いインジケーター値での売買によって利益を吸収することができます。 しかし、売ることによって収益性の高い領域は利用できません。

7.3. Chaikin

チャイキンオシレーターレポート

ATR と同じようにチャイキンオシレーターは、インジケーター値とトレードから利益の間の相互関係を明らかにしませんでした。

7.4. フォースインジケーター

フォースインジケーターレポート

フォースインジケーターの分析チャートは、依存関係も明らかにしませんでした。

7.5. 標準偏差

SndDev レポート

StdDev インジケーターの値に依存関係の分析は、買いオーダーの問題領域を明らかにすることができますが、売りトレードをフィルタリングする可能性はありません。

7.6. ボリュームインジケーター

ボリュームへの利益依存。

同様にボリュームインジケータのデータの分析で依存を検出できませんでした。

7.7. ビルウィリアムズ MFI

BW MFI

BW MFI は、カラー0でのみ開いている場合は、買いトレードのフィルタリングで利益を出すことができます。 しかし、売りトレードの依存の検出は失敗しました。

7.8. MACD

MACD のレポートMACD のレポート

MACD インジケーターのシグナルは、収益性の高い買いトレードをフィルタリングすることができます。 これは、シグナルラインがヒストグラムの上にあるとき買いトレードすれば可能です。 しかし、この分析は売りトレードには見られません。 同時に、このインジケーターは、ヒストグラムの下または同等のシグナルラインの成長している位置での売りトレードを除外して、損失を減らすことができます。

7.9. ADX

ADX インジケーターシグナルの分析は、トレードをフィルタリングすることはできません。

7.10. アリゲーター

アリゲーターのレポートアリゲーターのレポート

私の見解では、アリゲーターに対するフィルタリングの使用は、最も有望です。 アリゲーターにおけるトレードを行うためのパターンは、線の方向と位置の組み合わせにあります。 したがって、収益性の高い買いトレードが実行される場合があります。:

  • インジケータラインの位置は、売りトレンドとLIPやJAWのラインが上向きになります。
  • インジケーターラインの位置は、買いトレンドとLIPとTEETHの線が上向きに指示されていることを示しています。
  • トレンドは不定であり、TEETHおよびJAWのラインは下方に示されます。 

売りトレードでは、ミラーシグナルが使用されます。

8. 初期EAの修正

EAのトレードを分析する上で非常に広範なタスクを行っています。 さて、戦略のパフォーマンスにどのように影響するかを見てみましょう。 このため、記事 [1] のトレードシグナルモジュールには、上記の指定された分析に従って、フィルタールール付きのインジケーターを追加します。 モジュールに MACD とアリゲーターを追加することを推奨します。

順番にインジケーターフィルタを追加し、各フィルタの追加後にインジケーターにトレードを解決するための手順を循環的に実行することをお勧めします。 これは全体の戦略に各フィルタの影響をより明確にし、その複雑な影響を評価するのに役立ちます。 最初の段階の分析では、任意のインジケーターの値に利益依存を検出することはできませんが、以降の反復でそのような依存関係が表示されないことを意味しません。 これは今回はしませんが、今後役に立つかもしれません。

最初に、モジュールにインジケーターパラメータを追加します。

//| Parameter=JAW_Period,uint,13,JAW Period                                   |
//| Parameter=JAW_Shift,uint,8,JAW Shift                                      |
//| Parameter=TEETH_Period,uint,8,TEETH Period                                |
//| Parameter=TEETH_Shift,uint,5,TEETH Shift                                  |
//| Parameter=LIPS_Period,uint,5,LIPS Period                                  |
//| Parameter=LIPS_Shift,uint,3,LIPS_Shift                                    |
//| Parameter=Alligator_Method,ENUM_MA_METHOD,MODE_SMMA,Method                |
//| Parameter=Alligator_Price,ENUM_APPLIED_PRICE,PRICE_MEDIAN,Alligator Price |
//| Parameter=MACD_Fast,uint,12,MACD Fast                                     |
//| Parameter=MACD_Slow,uint,26,MACD Slow                                     |
//| Parameter=MACD_Signal,uint,9,MACD Signal                                  |
//| Parameter=MACD_Price,ENUM_APPLIED_PRICE,PRICE_CLOSE,MACD Price            |


パラメータをプライベートブロックに格納するための変数を追加しますが、保存する関数は public に追加します。

   uint              ci_MACD_Fast;
   uint              ci_MACD_Slow;
   uint              ci_MACD_Signal;
   ENUM_APPLIED_PRICE ce_MACD_Price;
   uint              ci_JAW_Period;
   uint              ci_JAW_Shift;
   uint              ci_TEETH_Period;
   uint              ci_TEETH_Shift;
   uint              ci_LIPS_Period;
   uint              ci_LIPS_Shift;
   ENUM_MA_METHOD    ce_Alligator_Method;
   ENUM_APPLIED_PRICE ce_Alligator_Price;
   void              JAW_Period(uint value)                 {  ci_JAW_Period  =  value;   }
   void              JAW_Shift(uint value)                  {  ci_JAW_Shift   =  value;   }
   void              TEETH_Period(uint value)               {  ci_TEETH_Period=  value;   }
   void              TEETH_Shift(uint value)                {  ci_TEETH_Shift =  value;   }
   void              LIPS_Period(uint value)                {  ci_LIPS_Period =  value;   }
   void              LIPS_Shift(uint value)                 {  ci_LIPS_Shift  =  value;   }
   void              Alligator_Method(ENUM_MA_METHOD value) {  ce_Alligator_Method  =  value;   }
   void              Alligator_Price(ENUM_APPLIED_PRICE value) {  ce_Alligator_Price=  value;   }
   void              MACD_Fast(uint value)                  {  ci_MACD_Fast   =  value;   }
   void              MACD_Slow(uint value)                  {  ci_MACD_Slow   =  value;   }
   void              MACD_Signal(uint value)                {  ci_MACD_Signal =  value;   }
   void              MACD_Price(ENUM_APPLIED_PRICE value)   {  ce_MACD_Price  =  value;   }

また、必要なデータの受信の初期化のインジケーターと関数を持つタスク用のクラスを追加する必要があります。 MACDに標準的なクラスを使用しました。 これまでのところは、アリゲーターの標準的なクラスが存在せず、移動平均の3つのクラスに置き換え、名前に応じてインジケータラインの名前に割り当てます。

protected:
   CiMACD            m_MACD;           //オブジェクトオシレーター
   CiMA              m_JAW;
   CiMA              m_TEETH;
   CiMA              m_LIPS;
     
   //---インジケーターの初期化メソッド
   bool              InitMACD(CIndicators *indicators);
   bool              InitAlligator(CIndicators *indicators);
   //データ取得メソッド
   double            Main(int ind)                     { return(m_MACD.Main(ind));      }
   double            Signal(int ind)                   { return(m_MACD.Signal(ind));    }
   double            DiffMain(int ind)                 { return(Main(ind+1)!=0 ? Main(ind)-Main(ind+1) : 0); }
   int               AlligatorTrend(int ind);
   double            DiffJaw(int ind)                  { return(m_JAW.Main(ind+1)!=0 ? m_JAW.Main(ind)/m_JAW.Main(ind+1) : 1); }
   double            DiffTeeth(int ind)                { return(m_TEETH.Main(ind+1)!=0 ? m_TEETH.Main(ind)/m_TEETH.Main(ind+1) : 1); }
   double            DiffLips(int ind)                 { return(m_LIPS.Main(ind+1)!=0 ? m_LIPS.Main(ind)/m_LIPS.Main(ind+1) : 1); }

次のステップで、InitIndicators に変更を加えて、EA ライブラリにインジケータを追加します。

bool CSignalKalman::InitIndicators(CIndicators *indicators)
  {
//---インジケーターの初期化と追加フィルタの時系列
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);
//--- initialize close serias
   if(CheckPointer(m_close)==POINTER_INVALID)
     {
      if(!InitClose(indicators))
         return false;
     }
//--- create and initialize MACD oscilator
   if(!InitMACD(indicators))
      return(false);
//--- create and initialize Alligator
   if(!InitAlligator(indicators))
      return(false);
//--- create and initialize Kalman Filter
   if(CheckPointer(Kalman)==POINTER_INVALID)
      Kalman=new CKalman(ci_HistoryBars,ci_ShiftPeriod,m_symbol.Name(),ce_Timeframe);
   
//---ok
   return(true);
  }

その後、関数に追加します。 同時に、インジケーターがフィルタとして機能することを覚えておいてください。 したがって、メインシグナルを受信した後にのみ、インジケータに接続可能です。

int CSignalKalman::LongCondition(void)
  {
   if(!CalculateIndicators())
      return 0;
   int result=0;
   //--- 
   if(cd_correction>cd_forecast)
     {
      if(Signal(1)>Main(1))
         result=80;
      else
        {
         switch(AlligatorTrend(1))
           {
            case 1:
              if(DiffLips(1)>1 && DiffTeeth(1)>1 && DiffJaw(1)<=1)
                 result=80;
              break;
            case -1:
              if(DiffLips(1)>1 || DiffJaw(1)>1)
                 result=80;
              break;
            case 0:
              if(DiffJaw(1)<1)
                {
                 if(DiffLips(1)>1)
                    result=80;
                 else
                    if(DiffTeeth(1)<1)
                       result=80;
                }
              break;
           }
        }
     }
   return result;
  }

類似の変更は ShortCondition 関数に加えられます。 トレード決定モジュールの完全なコードは添付ファイルで提供されます。

9. 変更した後の EA のテスト

トレーディング決定モジュールに変更を加えた後、新しいEAを作成します (トレーディングシグナルモジュールを使用したEAの作成についての詳細は、記事 [5]) に記載されています。 新たに作成した EA を、第2節の初期テストと同様のパラメータでテストしてみましょう。

テスト結果が示すように、EAのパラメータを変更することなく、フィルタの使用は0.75 から1.12 に利益率を増加させることができました。 すなわち、利益を得るために管理元の EA の損失パラメータです。 初めに、意図的に元のEAの非最適化パラメータを取ったことを思い出させてください。

繰り返しテスト繰り返しテスト繰り返しテスト

結論

この記事では、トレード履歴から標準的なインジケーターにフィルタシステムを導入する技術について実証しました。 テストすることによって、このシステムは、EAの運用収益性の具体的な結果を示すことができました。 提案システムは、既存のトレーディングシステムの最適化ではなく、新しいシステムを作成しようとするときに適用することができます。

References

  1. 価格動向予測におけるカルマンフィルタの使用
  2. HTML 形式のチャートと図
  3. どのくらいトレンドが続くか
  4. MQL5 でのトレンド決定のメソッド
  5. 相場における適応的手法の実践

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

#
 Name
Type 
Description 
1 Kalman.mqh  クラスライブラリ  カルマンフィルタクラス
2 SignalKalman.mqh  クラスライブラリ  カルマンフィルタによるトレーディングシグナルモジュール
3 SignalKalman+Filters.mqh  クラスライブラリ  インジケーターフィルタ追加後のカルマンフィルタによるトレーディングシグナルモジュール
4 Kalman_expert.mq5  EA  カルマンフィルタ適用の戦略に関するEA
5 Kalman+Filters.mq5  EA  カルマンフィルタ適用による戦略EAの修正
6 Deals_to_Indicators.mq5  EA  トレード履歴をインジケーターに導入するEA
7 Deal.mqh   クラスライブラリ  トレードに関する情報を保存するためのクラス
8 Parsing.mqh  クラスライブラリ  テストレポートからのトレード履歴解析のクラス
9 Value.mqh   クラスライブラリ  インジケーターバッファの状態でデータを保存するためのクラス
10 OneBufferArray.mqh  クラスライブラリ  1バッファインジケーターのデータ履歴を保存するクラス
11 StaticOneBuffer.mqh  クラスライブラリ  1バッファインジケーター統計の収集と解析のクラス
    12 ADXValue.mqh  クラスライブラリ  ADX インジケーターの状態でデータを保存するためのクラス
13 ADX.mqh  クラスライブラリ  ADX インジケーターのデータ履歴を保存するためのクラス
14 StaticADX.mqh  クラスライブラリ  ADX インジケーター統計の収集と分析のクラス
15 AlligatorValue.mqh  クラスライブラリ  アリゲーターのインジケーターの状態でデータを保存するためのクラス
16 Alligator.mqh  クラスライブラリ  アリゲーターのインジケーターのデータ履歴を保存するためのクラス
17 StaticAlligator.mqh  クラスライブラリ  アリゲーターのインジケーター統計の収集と分析のクラス
18 BWMFIValue.mqh  クラスライブラリ  BW MFI インジケータ状態でデータを保存するためのクラス
19 BWMFI.mqh  クラスライブラリ  BW MFI のデータ履歴を保存するためのクラス
20 StaticBWMFI.mqh  クラスライブラリ  BW MFI インジケーター統計の収集と分析のクラス
21 MACDValue.mqh  クラスライブラリ  MACD インジケーターのデータを保存するためのクラス
22 MACD.mqh  クラスライブラリ  MACD インジケーターのデータ履歴を保存するためのクラス
23 StaticMACD.mqh  クラスライブラリ  MACD インジケーター統計の収集と分析のクラス
24  Reports.zip  Archive  アーカイブには、ストラテジーテスターと分析レポートのEAのテスト結果があります。

MetaQuotes Software Corp.によりロシア語から翻訳された
元の記事: https://www.mql5.com/ru/articles/3968

添付されたファイル |
Reports.zip (360.75 KB)
取引における様々な移動平均の比較 取引における様々な移動平均の比較

7種類の移動平均(MA)が検討されており、それに対応する取引戦略が開発されています。単一の取引戦略における様々なMAのテストと比較が行われ、与えられた移動平均の適用の比較パフォーマンス特性が提供されています。

戦略バランス曲線の品質評価としての R 乗 戦略バランス曲線の品質評価としての R 乗

この記事では、カスタム最適化基準R乗の構築について扱います。 この基準は、戦略のバランス曲線の品質を推定し、安定した戦略を構築するために使うことができます。 今回は、このメトリックのプロパティと品質の推定に使用される、構造と統計的手法について説明します。

カルマンフィルタを用いた価格方向予測 カルマンフィルタを用いた価格方向予測

トレードで成功するには、ノイズ変動と価格変動を分けることができるインジケーターが必要です。 この記事では、最も有望なデジタルフィルタ、カルマンフィルタを検討します。 フィルタを描画して使用する方法について説明します。

通貨ペアバスケットをトレードするときに発生するパターンのテスト パート2 通貨ペアバスケットをトレードするときに発生するパターンのテスト パート2

通貨ペアバスケットをトレードするときに発生するパターンをテストし、トレード通貨ペアバスケットの記事で説明したメソッドを試していきます。 実際には、移動平均のクロスの複合 WPR チャートのパターンを使用できるかどうかを検討してみましょう。 もし使用できる場合は、適切な使用メソッドを検討する必要があります。