テクニカル分析のツールとしてのMTF指標

Alexander Lasygin | 18 6月, 2019

概論

私たちのほとんどは、現在の市場の状況を分析するプロセスはチャートの上位期間の見直しから始まるという意見を持ちます。これは、取引をする予定に進むまで起こります。この分析は成功した取引とビジネスへの専門的なアプローチのための条件の一つです。通常これのために同じツールのセットを使用すれば、私達は複数のウィンドウを開けるかまたはグラフの期間を切り替えます。そして、一次分析のプロセスが完了します。

次に何をしたらよいでしょうか?古いTFで何が起こっているのかを知らないままにしておくか、それともウィンドウとピリオドの間を「ジャンプ」し続けるか?H1以上の時間枠で作業する場合は、慎重に評価する時間があります。そしてそれがM1-M15である場合となると?しかし、私たちはこの情報を必要としており、時にはそれが不可欠です。他のタブのどこか、次のキーを押した後ではありません。これは、「Wolfe Waves」や「Elder Three Screens」など、さまざまなTFの同時評価に基づくMTF戦略に特に当てはまります。


このように行動することを余儀なくされているトレーダーは強い精神的および視覚的な緊張状態にあります。小さいTFで取引をする場合、古い期間の有益なシグナルを簡単に逃してしまいます。これらすべての事態は、結果的に、早急な決定の採用、取引の早期終了、または市場の逆転の瞬間の喪失につながります。そのような過ちの結果はよく知られています。このような状況では、私達は私達の経験または情報をいかに早く得るかに頼ることしかできません。

しかし、この問題に対する解決策があります。それは与えられた1つのまたはいくつかの取引商品のために異なるTFから情報を受け取り、それをスクリーン上に包括的に表示し、それによって市場が迅速に評価されることを可能にするインジケーターです。基本的な情報に加えて、市場動向の実際の状態を表示し、取引活動を推薦します。

アルゴリズムの特徴

従来のものとの主な違いは、すべての時間間隔または取引商品からの一般情報の処理とそれに続く現在の情報への転送です。マルチフレームインディケータは任意のタイプ(オシレーター、トレンド、ボリュームなど)またはそれらの組み合わせになります。それらは、設定で指定された時間間隔を考慮に入れて、それらの基本的なアルゴリズムに従って計算され、情報を送信します。

MTFバージョンでは、データを使用する時間間隔またはシンボルのリストを指定するための追加のパラメーター(またはパラメーターのグループ)を除いて、従来のMTFバージョンと比較して特別な設定は必要ありません。結果は、メインチャートウィンドウまたは個別に出力することができ、また、ツールタイプに基づいてグループを組み合わせてシグナルとして表示することもできます。

マルチタイムフレーム指標の分類

これらの指標はすべての標準クラスで表示されますが、それらのほとんどは複雑なタイプ、つまり計算とグラフィック要素の組み合わせです。

1. 情報クラス:これらのインジケーターはデータや追加情報を表示します。典型的な例はMultiTimeFrameインジケーターです。これは、各期間のローソクの終了時間、選択した通貨ペアの見積もりと入札、ローソクの状態(UP、DOWN、DOJI)、および数量を表示します。インディケータスクリーンは役に立つ情報でいっぱいですが、それは取引で使うのが難しく、参考のみにとどまります。

図 1. 情報インジケーター

このグループには、取引決定を下すために使用できる独立したツールもあります。複数の標準インジケーターの分析結果を表示するため、これらインジケーターをチャートにインストール(自動的に計算を実行し)するため、取引の推奨事項を生成する必要がなくなります。


図2. 情報インジケータシグナル



図3.情報インジケータシグナル

2. グラフィックインジケータは、同じツールのグラフィックを異なる時間枠で表示します。これは、3つの異なる時間枠からの標準エンベロープMA(13)です。

図4.グラフィックインジケーター

もう1つのタイプのグラフィック構成は、計算期間が異なるチャートのグループです。このアプローチは純粋な数学に基づいています。つまり、M5の確率指標(5.3.3)には、M15から(15.3.9)、M30から(30.3.18)のパラメータがあります。

図5. 計算期間が異なるグラフィックインジケーター

上記のバージョンは、何らかの予約を入れてMTFクラスを参照することができます。この方法は常に可能というわけではありませんが、この解決方法の欠点が非常に深刻であり、使用するのは適切ではありません。この方法の適用とその利点と欠点について詳しく説明します。

別のグループは、いわゆるシグナルインジケーターで構成されています。作業領域内のグラフィック構造が多すぎになることを避けるために、インジケーターはトレンドの方向や他のパラメータを反映するシグナル線またはグラフィックブロックを形成します。標準のMTF_Coralインディケータと上記のMTFソリューションはこのようになります。

6. シグナルインジケーター

別のグループを「ウィンドウ内のウィンドウ」と呼び、メインのチャートウィンドウに異なる時間枠または指標のチャートを表示することができます。


図7. 「ウィンドウ内ウィンドウ」インジケーター


図7.1. 「ウィンドウ内ウィンドウ」インジケーター

All_Woodies CCIソリューションのもう1つの例。


図7.1. 「ウィンドウ内ウィンドウ」タイプインジケータAll_Woodies CCI


別のグループには、MTFのボラティリティ指標が含まれています。これらはMTF Candlesを含みます。

8. ボラティリティインジケーターMTF Candles

実施方法

MTFインジケーターの主な種類を検討しました。ここで、線形実装の主な方法を示す簡単な例を見てみましょう。また各ソリューションの具体的な機能についても分析します。

多期間インジケーターMAインディケータを考えて、次のタスクを解決してみましょう。計算期間を変えてインディケータバージョンを作成し、3つの異なる時間枠を表示します。主なパラメータと変数を設定しましょう。

//---- indicator settings
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots   3
#property indicator_type1   DRAW_LINE
#property indicator_type2   DRAW_LINE

#property indicator_type3   DRAW_LINE
#property indicator_color1  Blue
#property indicator_color2  Red
#property indicator_color3  Lime
#property indicator_width1  1
#property indicator_width2  1
#property indicator_width3  1
//---- input parameters
input ENUM_TIMEFRAMES    tf1             = 1;              // Time Frame (1)
input ENUM_TIMEFRAMES    tf2             = 5;              // Time Frame (2)
input ENUM_TIMEFRAMES    tf3             = 15;             // Time Frame (3)
input int                maPeriod        = 13;             // MA period
input int                Shift           = 0;              // Shift
input ENUM_MA_METHOD     InpMAMethod     = MODE_SMA;      // Moving average method
input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE;   // Applied price
//---- indicator buffers
double ExtBuf1[];
double ExtBuf2[];
double ExtBuf3[];
//---- handles for moving averages
int    ExtHandle1;
int    ExtHandle2;
int    ExtHandle3;
//--- bars minimum for calculation
int    ExtBarsMinimum;
//---
int period1=0;
int period2=0;
int period3=0;

配列データを実装するときの条件は、それが関連付けられている時間枠が、変数で指定された時間枠以下であることです。

void OnInit()
  {
   int timeframe;
//---- indicator buffers mapping
   SetIndexBuffer(0,ExtBuf1,INDICATOR_DATA);
   SetIndexBuffer(1,ExtBuf2,INDICATOR_DATA);
   SetIndexBuffer(2,ExtBuf3,INDICATOR_DATA);
//---
   timeframe =_Period;
//---
   if(tf1>=timeframe)
   {
   period1=maPeriod*(int)MathFloor(tf1/timeframe);
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,period1-1);             //sets first bar from what index will be drawn
   PlotIndexSetInteger(0,PLOT_SHIFT,Shift);                      //line shifts when drawing
   PlotIndexSetString(0,PLOT_LABEL,"MA("+string(period1)+")");   //name for DataWindow
   ExtHandle1=iMA(NULL,0,period1,0,InpMAMethod,InpAppliedPrice); //get MA's handles
   }
//---- 
   if(tf2>=timeframe)
   {
   period2=maPeriod*(int)MathFloor(tf2/timeframe);
   PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,period2-1);             //sets first bar from what index will be drawn
   PlotIndexSetInteger(1,PLOT_SHIFT,Shift);                      //line shifts when drawing
   PlotIndexSetString(1,PLOT_LABEL,"MA("+string(period2)+")");   //name for DataWindow 
   ExtHandle2=iMA(NULL,0,period2,0,InpMAMethod,InpAppliedPrice); //get MA's handles
   }
//---- 
   if(tf3>=timeframe)
   {
   period3=maPeriod*(int)MathFloor(tf3/timeframe);
   PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,period3-1);             //sets first bar from what index will be drawn
   PlotIndexSetInteger(2,PLOT_SHIFT,Shift);                      //line shifts when drawing
   PlotIndexSetString(2,PLOT_LABEL,"MA("+string(period3)+")");   //name for DataWindow 
   ExtHandle3=iMA(NULL,0,period3,0,InpMAMethod,InpAppliedPrice); //get MA's handles
   }
//--- set accuracy
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
//--- bars minimum for calculation
   int per=MathMax(period3,MathMax(period1,period2));
   ExtBarsMinimum=per+Shift;
//--- initialization done
  }

メインサイクルは初期化と計算をチェックします。

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[])
  {
//--- check for rates total
   if(rates_total<ExtBarsMinimum)
      return(0); // not enough bars for calculation
//--- not all data may be calculated
   int calculated=BarsCalculated(ExtHandle1);
   if(calculated<rates_total&&period1!=0)
     {
      Print("Not all data of ExtHandle1 is calculated (",calculated,"bars ). Error",GetLastError());
      return(0);
     }
   calculated=BarsCalculated(ExtHandle2);
   if(calculated<rates_total&&period2!=0)
     {
      Print("Not all data of ExtHandle2 is calculated (",calculated,"bars ). Error",GetLastError());
      return(0);
     }
   calculated=BarsCalculated(ExtHandle3);
   if(calculated<rates_total&&period3!=0)
     {
      Print("Not all data of ExtHandle3 is calculated (",calculated,"bars ). Error",GetLastError());
      return(0);
     }
//--- we can copy not all data
   int to_copy;
   if(prev_calculated>rates_total || prev_calculated<0) to_copy=rates_total;
   else
     {
      to_copy=rates_total-prev_calculated;
      if(prev_calculated>0) to_copy++;
     }
//---- get ma buffers
   if(IsStopped()) return(0); //Checking for stop flag
   if(period1!=0)
   if(CopyBuffer(ExtHandle1,0,0,to_copy,ExtBuf1)<=0)
     {
      Print("getting ExtHandle1 is failed! Error",GetLastError());
      return(0);
     }
   if(IsStopped()) return(0); //Checking for stop flag
   if(period2!=0)
   if(CopyBuffer(ExtHandle2,0,0,to_copy,ExtBuf2)<=0)
     {
      Print("getting ExtHandle2 is failed! Error",GetLastError());
      return(0);
     }
   if(IsStopped()) return(0); //Checking for stop flag
   if(period3!=0)
   if(CopyBuffer(ExtHandle3,0,0,to_copy,ExtBuf3)<=0)
     {
      Print("getting ExtHandle3 is failed! Error",GetLastError());
      return(0);
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

結果を見てみましょう。

図9. MTFインディケータの実装

計算期間の増加を使用して、異なる指標で同じ指標を使用する例を検討しました。わずかな変更で、各行に個別の期間を設定する可能性を与えながら使用できます。この方法は非効率的に見えるかもしれません。期間を計算し、複数の指標を同時に適用することは非常に簡単です。ただし、場合によっては、この方法がすべての欠点にもかかわらず最適な方法です。そのうちの1つは、1つのウィンドウで2つ(3つ)の正規化されていないオシレーターを同時に観測する必要があることです。振幅範囲に起因して、これらのオシレーターは中心線に対してずれているため、この解釈は困難になります。この方法は上記の欠点を解消します。


マルチタイムフレームインジケーター

MQL5はよく知られているiClose()、iHigh()、iLow()、iOpen()、iTime()、iVolume()を使用しませんが、CopyTime()、CopyClose()、CopyHigh()、CopyLow()を提供します。 CopyOpen()、CopyTime()、CopyVolume()、およびiCustom、iMA、iCCI、iMACDなどの関数、およびその他の関数は、CopyBuffer()によって実装されています。およびその他の関数は、CopyBuffer()によって実装されています。 それぞれには長所と短所があり、私たちの例では、MQL5だけに触れます。私たちの測定基準では、M1からMN1までの完全なタイムラインリスト、すなわち26バージョンが必要です。さらに、複数の記号やツールを使用する必要がある場合、この数は何度も増えます。ほとんどの場合、履歴全体をコピーする必要はありません。ほとんどの情報指標では、バーの数は2本に制限されています。したがって、コードが長くなり過ぎないようにするには、これらのコマンドを別々の関数として記述し、それらを繰り返し呼び出すことをお勧めします。

時系列関数CopyClose()の場合、この関数は次のとおりです。

//+------------------------------------------------------------------+
double _iClose(string symbol,int tf,int index)
{
   if(index < 0) return(-1);

   double buf[];
   ENUM_TIMEFRAMES timeframe=TFMigrate(tf);
   if(CopyClose(symbol,timeframe, index, 1, buf)>0) 
        return(buf[0]);
   else return(-1);
}
//+------------------------------------------------------------------+

WPRを呼び出す方法。

//+------------------------------------------------------------------+
double _iWPR(string symbol,
                int tf,
                int period,
                int shift)
  {
   ENUM_TIMEFRAMES timeframe=TFMigrate(tf);
   int handle=iWPR(symbol,timeframe,period);
   if(handle<0)
     {
      Print("iWPRオブジェクトが作成されていません:エラー",GetLastError());
      return(-1);
     }
   else
      return(_CopyBuffer(handle,shift));
  }
//+------------------------------------------------------------------+
double _CopyBuffer(int handle,int shift)
  {
   double buf[];
if(CopyBuffer(handle,0,shift,1,buf)>0)
         return(buf[0]);

   return(EMPTY_VALUE);
  }
//+------------------------------------------------------------------+

複数の行がある場合、CopyBuffer関数は次のように書くことができます。

//+------------------------------------------------------------------+
double _CopyBuffer(int handle,int index,int shift)
  {
   double buf[];
   switch(index)
     {
      case 0: if(CopyBuffer(handle,0,shift,1,buf)>0)
         return(buf[0]); break;
      case 1: if(CopyBuffer(handle,1,shift,1,buf)>0)
         return(buf[0]); break;
      case 2: if(CopyBuffer(handle,2,shift,1,buf)>0)
         return(buf[0]); break;
      case 3: if(CopyBuffer(handle,3,shift,1,buf)>0)
         return(buf[0]); break;
      case 4: if(CopyBuffer(handle,4,shift,1,buf)>0)
         return(buf[0]); break;
default: break;
     }
   return(EMPTY_VALUE);
  }
//+------------------------------------------------------------------+

そして_iWPR関数はこの行を取ります

return(_CopyBuffer(handle,shift)

に変更します

return(_CopyBuffer(handle,0,shift)

どちらの場合もTFMigrate()は次のようになります。

//+------------------------------------------------------------------+
ENUM_TIMEFRAMES TFMigrate(int tf)
  {
   switch(tf)
     {
      case 0: return(PERIOD_CURRENT);
      case 1: return(PERIOD_M1);
      case 5: return(PERIOD_M5);
      case 15: return(PERIOD_M15);
      case 30: return(PERIOD_M30);
      case 60: return(PERIOD_H1);
      case 240: return(PERIOD_H4);
      case 1440: return(PERIOD_D1);
      case 10080: return(PERIOD_W1);
      case 43200: return(PERIOD_MN1);
      
      case 2: return(PERIOD_M2);
      case 3: return(PERIOD_M3);
      case 4: return(PERIOD_M4);      
      case 6: return(PERIOD_M6);
      case 10: return(PERIOD_M10);
      case 12: return(PERIOD_M12);
      case 20: return(PERIOD_M20);
      case 16385: return(PERIOD_H1);
      case 16386: return(PERIOD_H2);
      case 16387: return(PERIOD_H3);
      case 16388: return(PERIOD_H4);
      case 16390: return(PERIOD_H6);
      case 16392: return(PERIOD_H8);
      case 16396: return(PERIOD_H12);
      case 16408: return(PERIOD_D1);
      case 32769: return(PERIOD_W1);
      case 49153: return(PERIOD_MN1);      
      default: return(PERIOD_CURRENT);
     }
  }
//+------------------------------------------------------------------+

すでに説明したように、この計算タイプには限られた数の要素(バー)が必要です。しかし時々それは全体の履歴を計算することが賢明です。ここでは注意が必要です。時間枠が短いほど、時間枠が大きいほど履歴列が多くなることを忘れないでください。このようなツールを作成するときには、この事実を考慮に入れる必要があります。最も簡単な方法は、最小小節数を決定し、その値を計算に使用することです。より困難な方法は、各時間枠について別々にこの値を決定することです。多くの場合(特に情報インジケーターの場合)、データは列が閉じているときにのみ必要であるため、各時分割で下位の時間枠で古いデータを再計算する必要はありません。これを開発時に提供すると、コードの複雑さが大幅に軽減されます。

情報指標(図1、図2、図3)の開発は、従来の指標の開発と変わらないので、すぐに私が考える最も興味深いカテゴリであるグラフィカル指標のカテゴリに入りましょう。情報指標は現在の市況と使用されているシンボルに関するデータのみを必要とし、グラフィック指標はグラフィックに対する追加要件を持っています。M5の期間は5つのM1列からなり、M15は3つのM5列からなります。すなわち、M5上に線が形成されると、3つの列の間にM15から始まる線が引かれます。行の位置は固定されておらず、М15のローソクが閉じるまで変更することができます。したがって、ローソクを形成する時間を組み合わせる必要があります。これを達成するためにMAの例を使用しましょう。

//---- indicator settings
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
#property indicator_type1   DRAW_LINE
#property indicator_color1  Blue
#property indicator_width1  1
//---- input parameters
input ENUM_TIMEFRAMES    tf              = 5;              // Time Frame 
input int                maPeriod        = 13;             // MA period
input int                Shift           = 0;              // Shift
input ENUM_MA_METHOD     InpMAMethod     = MODE_SMA;       // Moving average method
input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE;    // Applied price
input  int               Bars_Calculated = 500;
//---- indicator buffers
double ExtMA[];
//---- handles for moving averages
int    MA_Handle;
//--- bars minimum for calculation
int    ExtBarsMinimum;
ENUM_TIMEFRAMES _tf;
int pf;
//--- Moving Average値は、インデックス内に保持されます 
int    bars_calculated=0; 
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   _tf=tf;
   ENUM_TIMEFRAMES timeframe;
   int draw_shift=Shift;// PLOT_SHIFTの初期値
   int draw_begin=maPeriod;// PLOT_DRAW_BEGINの初期値
//---
   timeframe=_Period;
   if(_tf<=timeframe)_tf=timeframe;// 時間枠が以下である場合現在値に等しく、PERIOD_CURRENTを設定
   pf=(int)MathFloor(_tf/timeframe);// PLOT_DRAW_BEGIN、PLOT_SHIFTおよび計算バーの数の係数を計算します
   draw_begin=maPeriod*pf;// PLOT_DRAW_BEGINを計算します
   draw_shift=Shift*pf;// PLOT_SHIFTを計算します
//---- indicator buffers mapping
   SetIndexBuffer(0,ExtMA,INDICATOR_DATA);
//--- 
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,draw_begin-pf);                      //sets first bar from what index will be drawn
   PlotIndexSetInteger(0,PLOT_SHIFT,draw_shift);                              //line shifts when drawing
   PlotIndexSetString(0,PLOT_LABEL,"MA("+string(tf)+" "+string(maPeriod)+")");//name for DataWindow
//---
   MA_Handle=iMA(NULL,_tf,maPeriod,0,InpMAMethod,InpAppliedPrice);            //get MA's handles
   if(MA_Handle==INVALID_HANDLE)
     {
      Print("getting MA Handle is failed! Error",GetLastError());
      return(INIT_FAILED);
     }
//--- set accuracy
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
//--- bars minimum for calculation
   ExtBarsMinimum=draw_begin+draw_shift;// 計算に必要な最小バー数を計算する
//--- initialization done
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//--- check for rates total
   if(rates_total<ExtBarsMinimum)
      return(0); // not enough bars for calculation
   int limit;
//--- 時系列インデックスを配列要素に適用する  
   ArraySetAsSeries(time,true);
   ArraySetAsSeries(ExtMA,true);
//--- detect start position
//--- 開始位置を検出
// --- およびバーの再計算サイクルのlimitの開始番号
   if(prev_calculated>rates_total || prev_calculated<=0|| calculated!=bars_calculated)// 指標計算の最初の開始をチェックします
     {
      limit=rates_total-ExtBarsMinimum-1; // すべてのバーを計算するための開始番号
     }
   else
     {
      limit=(rates_total-prev_calculated)+pf+1; // 新しいバーを計算するための開始番号
     }
   if(Bars_Calculated!=0)   limit=MathMin(Bars_Calculated,limit);

バーインデックス(iBarShift())で検索するのではなく、時間ごとに値を直接コピーします。

//--- main cycle
   for(int i=limit;i>=0 && !IsStopped();i--)
     {
      ExtMA[i]=_CopyBuffer(MA_Handle,time[i]);
     }
//---
   bars_calculated=calculated;
ここで上記の関数を使用してください。
//+--------- CopyBuffer MA Handle ----------------------------------+
double _CopyBuffer(int handle,datetime start_time)
  {
   double buf[];
   if(CopyBuffer(handle,0,start_time,1,buf)>0)
      return(buf[0]);

   return(EMPTY_VALUE);
  }
//+-------------------- END -----------------------------------------+

私達の結果はこのようになります。

図10. MTF指標ライン

この方法はすべての種類の線形指標に使用できます。主な欠点は上のスクリーンショットからわかります。MAの場合、このような振る舞いは問題ではなく、サポートや抵抗レベルの明確な定義を可能にするので、役に立つこともあります。しかし、私たちがパターンを使うオシレータにとって、この振る舞いはそのようなパターンの認識とレンダリングを妨げることがあります。さらに、線の外観が認識を超えて変化するので、この解決策は、WPR、CCIおよび同様の指標には受け入れられません。

この問題を解決するには、重み係数を考慮して最後のバーを計算する必要があります。両方のソリューションを使用できるようにする「Interpolate」グローバル変数を追加しましょう。

input bool               Interpolate     = true;
//--- main cycle
   for(int i=limit;i>=0 && !IsStopped();i--)
     {
      int n;
      datetime t=time[i];
      ExtMA[i]=_CopyBuffer(MA_Handle,t);
      if(!Interpolate) continue;
      //---
      datetime times= _iTime(t);
      for(n = 1; i+n<rates_total && time[i+n]>= times; n++) continue;
      double factor=1.0/n;
      for(int k=1; k<n; k++)
      ExtMA[i+k]=k*factor*ExtMA[i+n]+(1.0-k*factor)*ExtMA[i];
     }
//---

このバリエーションでは、現在のチャートに、_iTime関数を追加する必要があります。この関数は、開始時間に基づいてバー番号を決定します。

//+------------------------------------------------------------------+
datetime _iTime(datetime start_time)
{
   if(start_time < 0) return(-1);
   datetime Arr[];
   if(CopyTime(NULL,_tf, start_time, 1, Arr)>0)
        return(Arr[0]);
   else return(-1);
}
//+------------------------------------------------------------------+

これは今では普通の行のように見えます。

図11. MTFインジケーターライン_iTime

このような複雑で、リソースを集約したようなシステムの開発は不適切に見えるかもしれませんが、それらには長所があり、さらには不可欠になることさえあります。従来の平均化(MA、アリゲーターなど)が使用されている場合、計算期間の増加はMTFバージョンと比較していくらかの遅延を引き起こすかもしれません。これは、期待値が小さい期間に特に顕著です。

図12. MTF指標MAにおける遅延

図13. MTFインディケータ確率の遅れ

MAやアリゲーターのような単純な指標では、これはそれほど重要ではないかもしれません。しかし、MACD、AOなど、複数のMAから構成される複雑なシステムの場合、これは非常に重要になります。さらに、AOまたはACの平均期間を変更することはできません。滑らかでない線(WPR、CCIなど)を持つインジケーターの場合、計算期間が少し長くなっても非常にノイズが多いため、満足のいく結果が得られません。


図14 WRP MTFインディケーター


図15 CCI MTFインディケーター

図14〜図15は、この関数がアルゴリズムに提供されていないとき、それらが平滑化のために首尾よく使用できることを明確に示しています。

その直接の機能に加えて、このタイプはまたMetaTrader 5ストラテジーテスターの視覚テストパターンの欠如を補うことができます。取引のMTF EA取引を作成するとき、またはこの戦略の有効性を分析するとき、画面上の異なる時間枠でインディケータの位置を同時に観察することはできません。テスト後、使用されたサイクル数に応じて、一連のタブが表示されます。Anatoli Kazharskiの記事『MQL5 Cookbook:フレームワークに基づく「エルダーのトリプルフィルター」戦略』の例を見てみましょう。この戦略の考え方は、最初の期間が、毎週、毎日、または4時間など、最大の期間であるということです。主な傾向を特定するために使用されます。第2期間と第1期間の間には、1つまたは2つのレベルの違いがあります。これは修正を判断するために使用されます。3番目の期間は別のレベルであり、これは最良のエントリポイントを決定するために使用されます。

最初のフィルタでは、通常はM30-W1を使用してMACD(12、26、1)とEMAを13の周期で実行します。2番目のフィルタМ5-D1では、Stochastic Oscillator(5、3、3)が実行され、3番目のフィルタは、M1からH4まで使用され、主なトレンド方向のストップロス次数を設定します。

図16. エルダーのトリプルスクリーン

記事の著者はこの方法を使用することを主張しませんでしたが、テスト中およびテスト後に「トリプルフィルタ」の概念を保持しました。


図17. エルダーのトリプルスクリーンの戦略テスト

このオプションでは、エキスパートアドバイザの動作(戦略)を正しく分析する方法がありません。
私たちのツールを使って、より古典的な戦略版に近い私達のエキスパートアドバイザーのバージョンを作りましょう。上記のシグナルに基づいたエキスパートアドバイザーの作成は、従来のエキスパートアドバイザーと非常によく似ています。これがメインコードです。

#define EXPERT_MAGIC 1234502
//---
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\AccountInfo.mqh>
#include <Trade\OrderInfo.mqh>
//+------------------------------------------------------------------+
enum compTF
  {
   A, //m1-m5-m15
   B, //m5-m15-h1
   C, //m15-h1-h4
   E  //h1-h4-d1
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
input string s0="//--- input parameters Lots+Trailing ---//";
input double InpLots          =0.1; // Lots
input int    InpTakeProfit    =150; // Take Profit (in pips)
input int    InpStopLoss      =60;  // StopLoss (in pips)
input int    InpLevel_S       =20;  // Level Signal
input compTF InpTFreg         =2;
input string s1="//--- input parameters MA ---//";
input int                Signal_MA_PeriodMA      =21;                             // Period of averaging
input string s2="//--- input parameters MACD ---//";
input int                Signal_MACD_PeriodFast  =12;                             // Period of fast EMA
input int                Signal_MACD_PeriodSlow  =26;                             // Period of slow EMA
input string s3="//--- input parameters Stochastic ---//";
input int                Signal_Stoch_PeriodK    =5;                              //  K-period
input int                Signal_Stoch_PeriodD    =3;                              //  D-period
input string s4="//--- input parameters Trailing ---//";
//--- inputs for trailing
input int    InpTrailingStop  =25;  // Trailing Stop Level (in pips)
input int    InpOffset        =5;   // Distance from the price (in pips)
//---
int ExtTimeOut=10; // 取引操作間の秒数
int barsCalculated=3;
datetime t=0;
datetime time[];
//+------------------------------------------------------------------+
//| AC Sample expert class                                           |
//+------------------------------------------------------------------+
class CSampleExpert
  {
protected:
   double            m_adjusted_point;             // 3または5文字の値
   CTrade            m_trade;                      // 取引オブジェクト
   CSymbolInfo       m_symbol;                     // シンボル情報
   CPositionInfo     m_position;                   // 取引ポジション
   CAccountInfo      m_account;                    // アカウント情報
   COrderInfo        m_order;                      // オーダー情報 
   //--- indicators
   ENUM_TIMEFRAMES   mas_tf[3];                   // timeframesの配列
   int               handle_MACD;                 // MACD indicator handle
   int               handle_MA;                   // MA indicator handle
   int               handle_Stochastic;           // Stochastic indicator handle
   //--- indicator buffers
   double            macd_buff[];           // MACD indicator main buffer
   double            ma_buff[];             // MA indicator main buffer
   double            stoch_buff[];          // Stochastic indicator main buffer
   //---
   double            close[];
   double            open[];
   double            low[];
   double            high[];
   //--- 処理の為のインジケーターデータ
   double            macd_ind_0;
   double            macd_ind_1;
   double            ma_ind;
   double            stoch_ind_0;
   double            stoch_ind_1;
   int               level_stoch;
   //--- 処理の為のtrailing stopデータ
   double            m_traling_stop;
   double            m_take_profit;
   double            m_stop_losse;
public:
                     CSampleExpert(void);
                    ~CSampleExpert(void);
   bool              Init(void);
   void              Deinit(void);
   bool              Processing(void);

protected:
   bool              InitCheckParameters(const int digits_adjust);
   bool              Copy(void);              // 
   bool              InitIndicators(void);
   bool              LongModified(void);
   bool              ShortModified(void);
   bool              LongOpened(void);          //  Long条件を確認します
   bool              ShortOpened(void);         //  Short条件を確認します
   bool              OpenSellStop(void);        // SELLSTOPオーダーを設定します
   bool              OpenBuyStop(void);         // BUYSTOPオーダーを設定します
   bool              OrderModifySellStop(void); // SELLSTOPオーダーを設定します
   bool              OrderModifyBuyStop(void);  // BUYSTOPオーダーを設定します
   bool              DellSellStop(void);        // SELLSTOPオーダーを削除します
   bool              DellBuyStop(void);         // BUYSTOPオーダーを削除します
  };
//--- global expert
CSampleExpert ExtExpert;
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CSampleExpert::CSampleExpert(void) : m_adjusted_point(0),
                                     handle_MACD(INVALID_HANDLE),
                                     handle_Stochastic(INVALID_HANDLE),
                                     handle_MA(INVALID_HANDLE),
                                     macd_ind_0(0),
                                     macd_ind_1(0),
                                     stoch_ind_0(0),
                                     stoch_ind_1(0),
                                     ma_ind(0),
                                     m_traling_stop(0),
                                     m_take_profit(0)
  {
   ArraySetAsSeries(macd_buff,true);
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CSampleExpert::~CSampleExpert(void)
  {
  }
//+------------------------------------------------------------------+
//| 入力パラメータの初期化と検証                                         |
//+------------------------------------------------------------------+
bool CSampleExpert::Init(void)
  {
//--- 一般情報を初期化します
   m_symbol.Name(Symbol());                  // symbol
   m_trade.SetExpertMagicNumber(EXPERT_MAGIC); // magic
   m_trade.SetMarginMode();
   m_trade.SetTypeFillingBySymbol(Symbol());
//--- tuning for 3 or 5 digits
   int digits_adjust=1;
   if(m_symbol.Digits()==3 || m_symbol.Digits()==5)
      digits_adjust=10;
   m_adjusted_point=m_symbol.Point()*digits_adjust;
//--- 取引のデフォルト偏差を設定します 
   m_traling_stop    =InpTrailingStop*m_adjusted_point;
   m_take_profit     =InpTakeProfit*m_adjusted_point;
   m_stop_losse      =InpStopLoss*m_adjusted_point;
//--- set default deviation for trading in adjusted points
   m_trade.SetDeviationInPoints(3*digits_adjust);
//---
   int x=InpTFreg;
   switch(x)
     {
      case 0: {mas_tf[0]=PERIOD_M1;mas_tf[1]=PERIOD_M5;mas_tf[2]=PERIOD_M15;}
      break;
      case 1: {mas_tf[0]=PERIOD_M5;mas_tf[1]=PERIOD_M15;mas_tf[2]=PERIOD_H1;}
      break;
      case 2: {mas_tf[0]=PERIOD_M15;mas_tf[1]=PERIOD_H1;mas_tf[2]=PERIOD_H4;}
      break;
      case 3: {mas_tf[0]=PERIOD_H1;mas_tf[1]=PERIOD_H4;mas_tf[2]=PERIOD_D1;}
      break;
     }
//---
   if(!InitCheckParameters(digits_adjust))
      return(false);
   if(!InitIndicators())
      return(false);
//--- 結果
   return(true);
  }
//+------------------------------------------------------------------+
//| 入力パラメータの確認                                                |
//+------------------------------------------------------------------+
bool CSampleExpert::InitCheckParameters(const int digits_adjust)
  {
//--- 初期データの確認をします
   if(InpTakeProfit*digits_adjust<m_symbol.StopsLevel())
     {
      printf("Take Profitは%dよりも大きい必要があります",m_symbol.StopsLevel());
      return(false);
     }
   if(InpTrailingStop*digits_adjust<m_symbol.StopsLevel())
     {
      printf("Trailing Stopは%dよりも大きい必要があります",m_symbol.StopsLevel());
      return(false);
     }
//--- 正しいロット数を確認します
   if(InpLots<m_symbol.LotsMin() || InpLots>m_symbol.LotsMax())
     {
      printf("Lotsは%fから%fまでの範囲にある必要があります",m_symbol.LotsMin(),m_symbol.LotsMax());
      return(false);
     }
   if(MathAbs(InpLots/m_symbol.LotsStep()-MathRound(InpLots/m_symbol.LotsStep()))>1.0E-10)
     {
      printf("金額が%fロットのステップと一致していません",m_symbol.LotsStep());
      return(false);
     }
//--- warning
   if(InpTakeProfit<=InpTrailingStop)
      printf("Warning: Trailing StopはTake Profitよりも小さい必要があります");
//--- 結果
   return(true);
  }
//+------------------------------------------------------------------+
//| インジケーターの初期化                                              |
//+------------------------------------------------------------------+
bool CSampleExpert::InitIndicators(void)
  {
//--- MACDインジケーターを作成します
   if(handle_MACD==INVALID_HANDLE)
     {
      //---
      handle_MACD=iCustom(NULL,0,"MTF\\Oscillators\\MTF_MACD",mas_tf[2],Signal_MACD_PeriodFast,Signal_MACD_PeriodSlow);
      //---
      if(handle_MACD==INVALID_HANDLE)
        {
         printf("MACDインジケーター作成中にエラーが発生しました");
         return(false);
        }
     }
//--- MAインジケーターの作成をします
   if(handle_MA==INVALID_HANDLE)
     {
      //---
      handle_MA=iCustom(NULL,0,"MTF\\Trend\\MA_MultiTF",mas_tf[2],Signal_MA_PeriodMA,0,MODE_EMA,PRICE_CLOSE);
      //---
      if(handle_MA==INVALID_HANDLE)
        {
         printf("MAインジケーターの作成時にエラーが発生しました");
         return(false);
        }
     }
//--- Stochasticインジケーターを作成します
   if(handle_Stochastic==INVALID_HANDLE)
     {
      //---
      handle_Stochastic=iCustom(NULL,0,"MTF\\Oscillators\\MTF_Stochastic",mas_tf[1],Signal_Stoch_PeriodK,Signal_Stoch_PeriodD);
      //---
      if(handle_Stochastic==INVALID_HANDLE)
        {
         printf("Stochasticインジケーターの作成中にエラーが発生しました");
         return(false);
        }
     }
//--- 結果
   return(true);
  }
//+------------------------------------------------------------------+
//|          ロングポジションを変更します                                |
//+------------------------------------------------------------------+
bool CSampleExpert::LongModified(void)
  {
   bool res=false;
//--- トレーリングストップを確認します
   if(InpTrailingStop>0)
     {
      if(m_symbol.Bid()-m_position.PriceOpen()>m_adjusted_point*InpTrailingStop)
        {
         double sl=NormalizeDouble(m_symbol.Bid()-m_traling_stop,m_symbol.Digits());
         double tp=m_position.TakeProfit();
         if(m_position.StopLoss()<sl || m_position.StopLoss()==0.0)
           {
            //--- ポジションを変更します
            if(m_trade.PositionModify(Symbol(),sl,tp))
               printf("Long position by %s to be modified",Symbol());
            else
              {
               printf("Error modifying position by %s : '%s'",Symbol(),m_trade.ResultComment());
               printf("Modify parameters : SL=%f,TP=%f",sl,tp);
              }
            //--- 変更があったため、エキスパートアドバイザを終了する必要があります
            res=true;
           }
        }
     }
//--- 結果
   return(res);
  }
//+------------------------------------------------------------------+
//|                    ショートポジションを変更します                    |
//+------------------------------------------------------------------+
bool CSampleExpert::ShortModified(void)
  {
   bool   res=false;
//--- トレーリングストップを確認します
   if(InpTrailingStop>0)
     {
      if((m_position.PriceOpen()-m_symbol.Ask())>(m_adjusted_point*InpTrailingStop))
        {
         double sl=NormalizeDouble(m_symbol.Ask()+m_traling_stop,m_symbol.Digits());
         double tp=m_position.TakeProfit();
         if(m_position.StopLoss()>sl || m_position.StopLoss()==0.0)
           {
            //--- ポジションを変更します
            if(m_trade.PositionModify(Symbol(),sl,tp))
               printf("Short position by %s to be modified",Symbol());
            else
              {
               printf("Error modifying position by %s : '%s'",Symbol(),m_trade.ResultComment());
               printf("Modify parameters : SL=%f,TP=%f",sl,tp);
              }
            //--- 変更があったため、エキスパートアドバイザを終了する必要があります
            res=true;
           }
        }
     }
//--- 結果
   return(res);
  }
//+------------------------------------------------------------------+
//| ロングポジションを開く条件を確認してください                           |
//+------------------------------------------------------------------+
bool CSampleExpert::LongOpened(void)
  {
   bool res=false;
   level_stoch=InpLevel_S;
//--- ロングポジション(BUY)の可能性を確認します
   if(stoch_ind_1<level_stoch && stoch_ind_0>level_stoch && macd_ind_1>macd_ind_0 && ma_ind<close[1] && ma_ind<open[1])//&& ma_ind<close[1] && ma_ind<open[1]
     {
      //--- エキスパートアドバイザを終了
      res=true;
     }
//--- 結果
   return(res);
  }
//+------------------------------------------------------------------+
//|         Buy Stopポジション開きます                                  |
//+------------------------------------------------------------------+
bool CSampleExpert::OpenBuyStop(void)
  {
   bool res=false;
   double tp=0,sl=0;
//---
   if(LongOpened())
     {
      res=true;
      //-- リクエストの宣言と初期化及び結果
      MqlTradeRequest request={0};
      MqlTradeResult  result={0};
      //--- 未決済オーダーの設定パラメータ
      request.action   =TRADE_ACTION_PENDING;                             // 取引操作タイプ
      request.symbol   =Symbol();                                         // シンボル
      request.deviation=5;                                                // 価格からの許容偏差
      request.volume   =InpLots;                                          // ロットあたりの量
      request.magic    =EXPERT_MAGIC;                                     // MagicNumberのオーダー
      double offset=InpOffset;                                            // 現在の価格からポイントを2倍して注文する
      double price;                                                       // 注文トリガーの価格
      double point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);                // ポイントサイズ
      int digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);           // 小数桁数(桁数)
      //--- 取引タイプ
      request.type=ORDER_TYPE_BUY_STOP;                                   // オーダータイプ
      price=high[1]+offset*m_adjusted_point;                              // 開始価格
      request.price=NormalizeDouble(price,digits);                        // 正規化された開始価格
      tp=price+m_take_profit;
      sl=price-m_stop_losse;
      request.sl       =NormalizeDouble(sl,_Digits);                       // 新しいストップロス値を構造体
      request.tp       =NormalizeDouble(tp,_Digits);                       // 新しいTake Profit値を構造体に追加する
      //--- リクエストの送信
      if(!OrderSend(request,result))
        {res=false;printf("OrderSend error %d",GetLastError());}           // リクエストを送信できなかった場合、エラーコードを出力する
      //--- 操作情報
      printf("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
      //--- エキスパートアドバイザを終了
     }
//--- 結果
   return(res);
  }
//+------------------------------------------------------------------+
//| ショートポジションの開始条件を確認します                              |
//+------------------------------------------------------------------+
bool CSampleExpert::ShortOpened(void)
  {
   bool res=false;
   level_stoch=100-InpLevel_S;
//--- ショートポジション(SELL)の可能性をチェックする 
   if(stoch_ind_1>level_stoch && stoch_ind_0<level_stoch && macd_ind_1<macd_ind_0 && ma_ind>close[1] && ma_ind>open[1])
     {
      //--- エキスパートアドバイザを終了
      res=true;
     }
//--- 結果
   return(res);
  }
//+------------------------------------------------------------------+
//|         Sell Stopポジションを開く                                  |
//+------------------------------------------------------------------+
bool CSampleExpert::OpenSellStop(void)
  {
   bool res=false;
   double tp=0,sl=0;
//---
   if(ShortOpened())
     {
      res=true;
      //-- リクエストの宣言と初期化及び結果
      MqlTradeRequest request={0};
      MqlTradeResult  result={0};
      //--- 未決済オーダーの設定パラメータ
      request.action   =TRADE_ACTION_PENDING;                             // 取引操作タイプ
      request.symbol   =Symbol();                                         // シンボル
      request.deviation=5;                                                // 価格からの許容偏差
      request.volume=InpLots;                                             // ロットあたりの量
      request.magic=EXPERT_MAGIC;                                         // MagicNumberのオーダー
      int offset=InpOffset;                                                // 現在の価格からポイントを2倍して注文する
      double price;                                                       // 注文トリガーの価格
      int digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);           // 小数桁数(桁数)
      request.type=ORDER_TYPE_SELL_STOP;                                  // オーダータイプ
      price=low[1]-offset*m_adjusted_point;                                          // 開始価格
      request.price=NormalizeDouble(price,digits);                        // 正規化された開始価格
      tp=price-m_take_profit;
      sl=price+m_stop_losse;
      request.sl       =NormalizeDouble(sl,_Digits);                       // 新しいストップロス値を構造体
      request.tp       =NormalizeDouble(tp,_Digits);                       // 新しいTake Profit値を構造体に追加する
      //--- リクエストの送信
      if(!OrderSend(request,result))
        {res=false;printf("OrderSend error %d",GetLastError());}     // リクエストを送信できなかった場合、エラーコードを出力する
      //--- 操作情報
      printf("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
      //--- エキスパートアドバイザを終了
     }
//--- 結果
   return(res);
  }
//+------------------------------------------------------------------+
//| メインの関数はもしポジションがある場合はtrueを返します                  |
//| 処理します                                                         |
//+------------------------------------------------------------------+
bool CSampleExpert::Processing(void)
  {
//   MqlDateTime dt;
//--- 更新速度
   if(!m_symbol.RefreshRates())
      return(false);
//--- 更新インジケーター
   if(BarsCalculated(handle_Stochastic)<barsCalculated)
      return(false);
   if(CopyBuffer(handle_Stochastic,0,0,barsCalculated,stoch_buff)!=barsCalculated)
      return(false);
//---
   if(BarsCalculated(handle_MACD)<barsCalculated)
      return(false);
   if(CopyBuffer(handle_MACD,0,0,barsCalculated,macd_buff)!=barsCalculated)
      return(false);
//---
   if(BarsCalculated(handle_MA)<barsCalculated)
      return(false);
   if(CopyBuffer(handle_MA,0,0,barsCalculated,ma_buff)!=barsCalculated)
      return(false);
//---
   if(!Copy())return(false);
//--- コーディングとアクセスのスピードアップのために
//--- データは内部変数内に配置されます
   macd_ind_0   = macd_buff[1];
   macd_ind_1   = macd_buff[0];
   ma_ind       = ma_buff[1];
   stoch_ind_0  = stoch_buff[1];
   stoch_ind_1  = stoch_buff[0];

//--- 正しく終了することが大切です ...   
//--- 始めにポジションがあるか確認し、それを選択してください
   bool bord=false,sord=false;
   ulong ticket;
//+---------オープンポジションがあり、トレーリングストップが有効になっている-----------+
   if(m_position.Select(Symbol()) && PositionsTotal()>0 && m_traling_stop!=0)
     {
      if(m_position.PositionType()==POSITION_TYPE_BUY)
        {
         bord=true;
         //--- ロングポジションを変更する
         if(LongModified())
            return(true);
        }
      else
        {
         sord=true;
         //---ショートポジションを変更する
         if(ShortModified())
            return(true);
        }
     }
//+----- STOPオーダーを使用した取引------------------------------------+
// このサイクルでは、確立された全ての未決済注文を繰り返します
   for(int i=0;i<OrdersTotal();i++)
     {
      // 各注文を選択してチケットを取得します
      ticket=OrderGetTicket(i);
      // Buy Stopオーダーを受け付けます
      if(m_order.OrderType()==ORDER_TYPE_BUY_STOP)
        {
         // Buy Stop注文があることを示すフラグを設定
         bord=true;
         //--- 正しく市場に参入、必要に応じて順序を移動させることが重要です 
         if(bord)OrderModifyBuyStop(); // BUYSTOPオーダーを変更します
        }
      // Sell Stop注文を処理します
      if(m_order.OrderType()==ORDER_TYPE_SELL_STOP)
        {
         // Sell Stop注文があることを示すフラグを設定 
         sord=true;
         //--- 正しく市場に参入、必要に応じて順序を移動させることが重要です 
         if(sord)OrderModifySellStop(); // SELLSTOPオーダーを変更します
        }
     }
//--- 注文がない場合 ------------------------------------+
   if(!sord)if(OpenSellStop()){sord=true;return(true);}
   if(!bord)if(OpenBuyStop()){bord=true;return(true);}
//--- ポジションを処理せずに終了します
   return(false);
  }
//+------------------------------------------------------------------+
//| 先に設置されたSell Stop注文のパラメータを変更する                     |
//+------------------------------------------------------------------+
bool CSampleExpert::OrderModifySellStop(void)
  {
   bool res=true;
   ulong ticket;
   double tp=0,sl=0;
   double offset=InpOffset;                                            // 現在の価格からポイントを2倍して注文する
   double price;                                                       // 注文トリガーの価格
   int digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);           // 小数桁数(桁数)
                                                                       // リクエストの宣言と初期化及び結果
   MqlTradeRequest request={0};
   MqlTradeResult  result={0};
   int total=OrdersTotal(); // 設定された未決済注文の数
//--- 設定された全ての未決済注文の数
   for(int i=total-1; i>=0; i--)
     {
      // 各注文を選択してチケットを取得します
      ticket=OrderGetTicket(i);
      // Sell Stop注文を処理します
      if(m_order.OrderType()==ORDER_TYPE_SELL_STOP)
        {
         ulong  magic=OrderGetInteger(ORDER_MAGIC);               // MagicNumberオーダー
         //--- もしMagicNumberが一致した場合
         if(magic==EXPERT_MAGIC)
           {
               price=low[1]-offset*m_adjusted_point;                         // 開始価格 
            if(price>m_order.PriceOpen()) // 条件を確認
            if(low[1]>low[2]) // 条件を確認
              {
               request.action=TRADE_ACTION_MODIFY;                           // 取引操作タイプ
               request.order = OrderGetTicket(i);                            // オーダーチケット
               request.symbol   =Symbol();                                   // シンボル
               request.deviation=InpOffset;                                  // 価格からの許容偏差
               price=low[1]-offset*m_adjusted_point;                         // 開始価格 
               request.price=NormalizeDouble(price,digits);                  // 正規化された開始価格
               tp=price-m_take_profit;
               sl=price+m_stop_losse;
               request.sl       =NormalizeDouble(sl,_Digits);                // 新しいストップロス値を構造体
               request.tp       =NormalizeDouble(tp,_Digits);                // 新しいTake Profit値を構造体に追加する
               //--- リクエストの送信
               if(!OrderSend(request,result))
                 {
                  // Sell Stop注文があることを示すフラグを設定
                  res=true; printf("OrderSend error %d",GetLastError());
                 }  // リクエストを送信できなかった場合、エラーコードを出力する
               //--- 操作情報   
               printf("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
              }
           }
        }
     }
   return(res);
  }
//+------------------------------------------------------------------+
//|先に設置されたSell Stop注文のパラメータを変更する                      |
//+------------------------------------------------------------------+
bool CSampleExpert::OrderModifyBuyStop(void)
  {
   bool res=true;
   ulong ticket;
   double tp=0,sl=0;
   double offset=InpOffset;                                            // 現在の価格からポイントを2倍して注文する
   double price;                                                       // 注文トリガーの価格
   int digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);           // 小数桁数(桁数)
                                                                       //-- リクエストの宣言と初期化及び結果
   MqlTradeRequest request={0};
   MqlTradeResult  result={0};
   int total=OrdersTotal(); // 設定された未決済注文の数
//--- 設定された全ての未決済注文の数
   for(int i=total-1; i>=0; i--)
     {
      // 各注文を選択してチケットを取得します
      ticket=OrderGetTicket(i);
      // Buy Stopオーダーを受け付けます
      if(m_order.OrderType()==ORDER_TYPE_BUY_STOP)
        {
         ulong  magic=OrderGetInteger(ORDER_MAGIC);               // MagicNumberオーダー
         //--- もしMagicNumberが一致した場合
         if(magic==EXPERT_MAGIC)
           {
               price=high[1]+offset*m_adjusted_point;                        // 開始価格 
            if(price<m_order.PriceOpen()) // 条件を確認
              {
               request.action=TRADE_ACTION_MODIFY;                           // 取引操作タイプ
               request.symbol   =Symbol();                                   // シンボル
               request.action=TRADE_ACTION_MODIFY;                           // 取引操作タイプ
               request.order = OrderGetTicket(i);                            // オーダーチケット
               request.symbol   =Symbol();                                   // シンボル
               request.deviation=InpOffset;                                  // 価格からの許容偏差
               //--- テイクプロフィットとストップロスオーダー価格の設定 

               request.price=NormalizeDouble(price,digits);                  // 正規化された開始価格
               tp=price+m_take_profit;
               sl=price-m_stop_losse;
               request.sl       =NormalizeDouble(sl,_Digits);                       // 新しいストップロス値を構造体
               request.tp       =NormalizeDouble(tp,_Digits);                       // 新しいTake Profit値を構造体に追加する
               //--- リクエストの送信
               if(!OrderSend(request,result))
                 {
                  // Sell Stop注文が削除されていないことを示すフラグを設定
                  res=true;
                  printf("OrderSend error %d",GetLastError());
                 }  // リクエストを送信できなかった場合、エラーコードを出力する
               //--- 操作情報   
               printf("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);
              }
           }
        }
     }
   return(res);
  }
//+------------------------------------------------------------------+
//| エキスパートアドバイザの初期化機能                                    |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//--- 必要なすべてのオブジェクトを作成します
   if(!ExtExpert.Init())
      return(INIT_FAILED);
//--- ok
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| ティック処理関数                                                   |
//+------------------------------------------------------------------+
void OnTick(void)
  {
   static datetime limit_time=0; // 最終取引処理時間+タイムアウト
//--- タイムアウトの場合処理を行わない
   if(TimeCurrent()>=limit_time)
     {
      //--- データをチェックする
      if(Bars(Symbol(),Period())>barsCalculated)
        {
         //--- タイムアウトの制限時間を秒単位で変更する
         if(ExtExpert.Processing())
            limit_time=TimeCurrent()+ExtTimeOut;
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CSampleExpert::Copy(void)
  {
//--- コピーする数 
   int copied=3;
//---
   ArrayResize(high,copied);
   ArrayResize(low,copied);
   ArrayResize(close,copied);
   ArrayResize(open,copied);
//+------ 配列インデックスの方向を設定します ---------------------+
   ArraySetAsSeries(high,true);
   ArraySetAsSeries(low,true);
   ArraySetAsSeries(close,true);
   ArraySetAsSeries(open,true);
//--- バーの価格をコピーする 
   if(CopyHigh(NULL,mas_tf[0],0,copied,high)<0)
     {printf("No copied High",GetLastError());return(false);}
//---
   if(CopyLow(NULL,mas_tf[0],0,copied,low)<0)
     {printf("No copied Low",GetLastError());return(false);}
//---
   if(CopyClose(NULL,mas_tf[2],0,copied,close)<0)
     {printf("No copied Close",GetLastError());return(false);}
//---
   if(CopyOpen(NULL,mas_tf[2],0,copied,open)<0)
     {printf("No copied Open",GetLastError());return(false);}
//---
   return(true);
  }
//+------------------------------------------------------------------+


このようなツールを使用すると、異なる見方ができます。



図18. 実装したMTFツールを使用したエキスパートアドバイザのテスト

これで、エキスパートアドバイザの動作を観察するだけでなく、テスターの広大な機能から恩恵を受けるために、起こりうる欠点を分析することもできます。


まとめ

MQL5ソフトウェアモジュールの作者はこのようなアルゴリズムを作成する直接的な可能性を提供していませんが、これらの測定基準は非常に役に立ちます。場合によっては、さまざまな時間枠で同時に市場状態分析を実行し、ストラテジーテスタの効率を向上させ、滑らかさを向上させることができます。与えられたコード例には欠点があるかもしれないので、MQL5プログラミング言語を使用してMTF指標のアイデアをさらに開発する機会がたくさんあると思います。

添付ファイル

名前 タイプ パス
MA_MultiPeriod Trend MQL5\Indicators\MA_MultiPeriod.mq5
MA_MultiTF Trend MQL5\Indicators\MTF\Trend\MA_MultiTF.mq5
MTF_BB Trend MQL5\Indicators\MTF\Trend\MTF_BB.mq5
MTF_Envelopes Trend MQL5\Indicators\MTF\Trend\MTF_Envelopes.mq5
MTF_ParabolicSAR Trend MQL5\Indicators\MTF\Trend\MTF_ParabolicSAR.mq5
MTF_StdDev Trend MQL5\Indicators\MTF\Trend\MTF_StdDev.mq5
MTF_CCI Oscillators MQL5\Indicators\MTF\Oscillators\MTF_CCI.mq5
MTF_Force_Index Oscillators MQL5\Indicators\MTF\Oscillators\MTF_Force_Index.mq5
MTF_MACD Oscillators MQL5\Indicators\MTF\Oscillators\MTF_MACD.mq5
MTF_Momentum Oscillators MQL5\Indicators\MTF\Oscillators\MTF_Momentum.mq5
MTF_RSI Oscillators MQL5\Indicators\MTF\Oscillators\MTF_RSI.mq5
MTF_RVI Oscillators MQL5\Indicators\MTF\Oscillators\MTF_RVI.mq5
MTF_Stochastic Oscillators MQL5\Indicators\MTF\Oscillators\MTF_Stochastic.mq5
MTF_WPR  Oscillators  MQL5\Indicators\MTF\Oscillators\MTF_WPR.mq5
Triple Screen Trading System 1.0  Expert