English Русский 中文 Español Deutsch Português
チャネルを利用したトレードのためのエキスパートアドバイザー

チャネルを利用したトレードのためのエキスパートアドバイザー

MetaTrader 4 | 4 11月 2015, 14:30
1 984 0
Genkov
Genkov

はじめに

私の経験をMQL4の基礎だけは分かる初心者トレーダーの皆さんとシェアし、チャネルを利用したトレードの助けとなるプログラムを紹介したいと思います。チャネルでのトレードを始める前に、チャネルの重要な原則と、どのようにチャネルのサイズと方向が値動きによって変わるのか、明確な理解を持っていなくてはいけません。どのチャネルラインもチャート上に見えるバーの範囲内で完全に形作られたフラクタルに基づいてプロットされます。


チャネルを利用したトレードのための半自動エキスパートアドバイザー

標準プログラムのスタート部分をここに示します。添付ファイルの中にも入っているものです。

まず最初に期間に応じてフラクタルパターンを探すためのバーの本数を決めましょう。また、チャート上に表示すべき矢印のためのスペース値(*表示場所のことです。バーの何ポイント真上・真下かの値です)も設定します。

switch (Period())
{
case 1:     B_F=12; space=0.0002; break;
case 5:     B_F=48; space=0.0003; break;
case 15:    B_F=24; space=0.0004; break;
case 30:    B_F=24; space=0.0004; break;
case 60:    B_F=12; space=0.0007; break;
case 240:   B_F=15; space=0.0012; break;
case 1440:  B_F=10; space=0.0030; break;
case 10080: B_F=6;  space=0.0040; break;
}

どのチャネルラインが描けるか、基準点(バー)を探すことからチャネルの形成を始めます。上部か下部の特定のポイントのため、グローバル変数のレベルにおける以下の条件を導入します。:

  • Extrem = (0) - フラクタルは発見されない
  • Extrem = (1) - 上部のフラクタルが発見される // 正の数
  • Extrem = (-1) - 下部のフラクタルが発見される // 負の数

基準点とチャート上のそれらの位置を設定するため、以下のように初期不確定値をセットしましょう。:

NB1=-1; NB2=-1; Extrem=0;

テストは潜在的な「フラクタルフォーメーション」の見方において3番目のバー(「0」とカウント)から始めましょう。

TestBar=2;  // テストされたバーの本数

テストされたバーが上記で定義されたレンジ内の最大値か最小値と合致する場所を特定するため、「while文」ループ処理を加えます。ループ処理の条件はバー数の負の値であることの数式になるでしょう。加えて、テストされたバーの数がテストされるバーの総本数より小さくならなければいけません。

while(((NB1==-1) || (NB2==-1)) && (TestBar<AllB))

最初に極値のポイントが低いとみて、それらが最小値と合致するかどうかバーをテストしましょう。2つポイントがみつかったら、ループ処理の条件はfalseになりオペレーターの実行は終了されます。

以下は下部のチャート上の点を特定するための「while文」ループ処理のスニペットです。上部の基準点の検索はも同様の方法によってなされます。

//「フラクタルを見つける」ことができるように3番目のバー(「0」とカウント)からカウント
TestBar=2;  // テストされたバーの本数
NB1=-1; NB2=-1; Extrem=0;   // バーの本数と極値が決まっていないものと仮定 
while(((NB1==-1) || (NB2==-1)) && (TestBar<AllB))
  {//w1
// -------------------------------------------------------------------------------------+
// もし極値が(1)より小さい(2つのオプション値は "0" と"-1"), 
//  最小値の値の指標が考慮中のバーの指標と同時に起こると仮定
// -------------------------------------------------------------------------------------+   
   if((Extrem<1) && (TestBar==iLowest(Symbol(),Period(),MODE_LOW,B_F*2+1,TestBar-B_F)))
     {//w2
      // この瞬間に極値が存在しない時"0"
      if(Extrem==0)
        {//w3
         // 割り当て:(-1)の値を見つかった極値のポイントに割り当てる。  
         // これを低い極値とする。; 数を特定したバー(NB1)と値の変数(Pr1)に割り当てる   
         Extrem=-1; NB1=TestBar; Pr1=Low[NB1];
        }//-w3
      else  if(Extrem!=0) //1番目のポイントが先に見つかった場合
                          // さもなくな数と値の変数にポイント2を割り当てる
        {//w4
         NB2=TestBar; Pr2=Low[NB2];
        }//-w4
      // コントロールのため、値はプリントされる- Print("   bar #= ",NB2," price value= ",Pr2); 
     }//-w2
// -------------------------------------------------------------------------------------+

1つだけポイントがみつかったならば、ループ処理の条件はtrueのままでオペレーターは高い極値まで実行します。2つの高いポイントが見つけられなかったならば、それは現在はチャネルを形成するポイントがないことを意味します。

if((NB1==-1) || (NB2==-1)) // 直近の AllB バーで基準点が見当たらない

2つの基準点が利用可能なら、プライスチェンジのレートを計算します。:

RatePr=(Pr2-Pr1)/(NB2-NB1);

それから「0」バーの最初の基準点の投影として最初のチャネルラインの標点を探します。:

double Tk1=Pr1-NB1*RatePr;

チャネルラインの2番目の参考ポイントはチャートの左側の見えるレンジ内、たとえば2番目の基準点から左側50本のバーから特定されます。

double Tk2=Tk1+(NB2+50)*RatePr;

反対側のチャネルラインを特定したラインと並行にプロットしましょう。:

3番目の基準点を見つけるため、NB1からNB2まで(または0からNB2まで、あるいは2番目のバーからNB2まで)、他の2つの基準点の間にあるバーをテストしましょう。テストは発見されたポイントとは反対の方向にある極値に基づいておこなわれます。例えば、特定したポイントが高めのチャートポイントであれば、バーは安値に基づいてテストされます。3番目の基準点を発見した後、反対側のチャネルラインの他の2つの参考ポイントは同じセクションにあると判断されます。

以下のスニペットを注釈とともに紹介します。

反対側のチャネルラインを特定したラインと並行にプロット
//反対側のチャネルラインの基準点を探す: 
// 検索の出発点として2番目のバーの最小値をとる
Tk3=Low[2]-2*RatePr; // "0"バーに2番目のバーを置換
for(i=3;i<=NB2;i++) // 3番目のバーから検索をスタート  
  {//2(1)Up
   if(Low[i]<Tk3+i*RatePr) // "0" バーに置換した値の最小値を使用
     {//3(1)Up
      Tk3=Low[i]-i*RatePr; // 3番目の参考ポイント("0" バーの置換)
      Pr5=Low[i];          //下部のチャネルラインのための3番目基準点
      NB5=i;               // 3番目基準点のバーの数
     }//-3(1)Up
  }//-2(1)Up

3番目の基準点が見つかった後、チャート上に3点描くことができます。前もって存在している基準点は削除していきます。

チャート上に基準点を描くプログラムのスニペットを以下に示します。

ObjectDelete("Rep1"); ObjectDelete("Rep2"); ObjectDelete("Rep3"); ObjectDelete("Rep5");
   ObjectCreate("Rep1",OBJ_ARROW, 0, TmR1, Pr1+2*space);
      ObjectSet("Rep1", OBJPROP_COLOR, Yellow);
      ObjectSet("Rep1", OBJPROP_ARROWCODE,72); 
   ObjectCreate("Rep2",OBJ_ARROW, 0, TmR2, Pr2+2*space);
      ObjectSet("Rep2", OBJPROP_COLOR, Yellow);
      ObjectSet("Rep2", OBJPROP_ARROWCODE,72); 
   ObjectCreate("Rep5",OBJ_ARROW, 0, TmR5, Pr5-space);
      ObjectSet("Rep5", OBJPROP_COLOR, Yellow);
      ObjectSet("Rep5", OBJPROP_ARROWCODE,71);
  ObjectDelete("Cross2");

結果、基準点の上部/下部に印をみることができます。(以下を見てください。)

3つの基準点と4つの参考ポイントを特定するとチャート上にラインを引くことができます。:

DelObj1();  
ObjectCreate("Tr1",OBJ_TREND,0,Tm2,Tk2,Tm1,Tk1);
  ObjectSet("Tr1",OBJPROP_COLOR,Lime); 
  ObjectSet("Tr1",OBJPROP_WIDTH,1); //2
  ObjectSet("Tr1",OBJPROP_STYLE,STYLE_SOLID); 
ObjectCreate("Tr2",OBJ_TREND,0,Tm2,Tk4,Tm1,Tk3); 
  ObjectSet("Tr2",OBJPROP_COLOR,Lime); 
  ObjectSet("Tr2",OBJPROP_WIDTH,1); //2
  ObjectSet("Tr2",OBJPROP_STYLE,STYLE_SOLID); 
ObjectCreate("Med",OBJ_TREND,0,Tm2,(Tk2+Tk4)/2,Tm1,(Tk1+Tk3)/2);
  ObjectSet("Med",OBJPROP_COLOR,Lime); 
  ObjectSet("Med",OBJPROP_WIDTH,1); 
  ObjectSet("Med",OBJPROP_STYLE,STYLE_DOT);

直近6本のバーを使ってチャネルとチャネルとの境界の中間値を計算しましょう。:

for(int i=0;i<6;i++)
  {
   TLUp_[i]=Tk1+i*RatePr;
   TLDn_[i]=Tk3+i*RatePr;
   Med_[i]=(TLUp_[i]+TLDn_[i])/2;
  }

もし値がチャネルラインをクロスしたら、アスタリスクでマークし効果音通知を加えます。:

if(Bid>TLUp_[0])
  {
   bool TrUp=true; //bool TrDn=false; 
   ObjectDelete("Cross1");  ObjectDelete("Cross2");
   ObjectCreate("Cross1",OBJ_ARROW,0,Tm1,High[1]+2*space);
   ObjectSet("Cross1",OBJPROP_COLOR,DeepPink);
   ObjectSet("Cross1",OBJPROP_ARROWCODE,171);
   PlaySound("alert.wav"); // ファイルはテーミナルディレクトリ\soundsの下位に保存しなければいけません
  }

直近のバーで完全に形作られたフラクタルがあるなら、チャートにマークします。:

ObjectDelete("Fraktal"+(q-1));  //ObjectDelete("Frakt"+(w-1));
ObjectCreate("Fraktal"+q,OBJ_ARROW, 0, Time[2], High[2]+2*space+0.0002);
ObjectSet   ("Fraktal"+q, OBJPROP_COLOR, Orchid);
ObjectSet   ("Fraktal"+q, OBJPROP_ARROWCODE,217);

ある特性をとらえてチャネルそれ自体を作るためスニペットをプログラムしました。

ここからチャネルを利用したトレードの可能性について述べます。

ある仮定ですが、チャネルは上方向で現在のローソク足は下降しチャネルの下部の境界に近付くか越えるかするとします。この場合、起こり得る値動きの習性を以下に示します。:

  • 値は下部の境界に届く前に上方向へ反転する。;
  • 値は下部の境界に達し上方向へ反転する。;
  • 値はチャネルラインを越えてその後反転する。;
  • 下部の境界を越えて、値は下方向への動きを継続する(下方向ブレイクアウト)。

下部の境界を越える時というのはバーの最小値が越える時を意味していることに注意してください。

この状況に直面した時、最初の3つの値動きパターンは買いポジションをオープンするのに適しています。それらを見ていきましょう。このエキスパートアドバイザーのチャネルは完全に形作られたフラクタルに基づいていることに留意してください。そのため、フラクタルが完成した後、すなわち直近3本のバーでチャネルはその方向を変えるかもしれない可能性があり、考慮に入れておく必要があります。

最初のパターンを復習しましょう。まず、最小値を持つバーに続くバーは前のバーの最小値より高い値でオープンするでしょう。そして、(左から右に数えて)3番目のバーの最小値は最初のバーの最小値より高くもあるでしょう。したがって、(左から右に数えて、すなわち0のバーから数えて)バー3はフラクタルフォーメーションに関する最小値ということです。そしてもしチャネルの上昇方向が変わらなければ買いポジションをオープンすることができます。

それではチャネルの方向の変化について述べていきます。下部の基準点をもとにチャネルが描かれたならば、フラクタルの最小値が下部のチャネルラインより上にあるのでチャネル方向は変わりません。

上部の基準点をもとにチャネルが描かれたならば、チャネル方向はそのまま同じです。最初のパターンから生じる疑問は下部のチャネル境界と、境界の近くに形成されたフラクタルの最小値との間の差異をどれだけ十分に考慮できるかということです。この差異の大きさは主にチャネルのサイズによります。

ルールにのっとった3番目の値動きパターンは、チャネルの傾きの変化を導き、時にフラクタルが下部のチャネル境界より下に形作られることでチャネル方向の変化という結果さえ起こします。形成されたフラクタルの値が最初の参考ポイントより低く2番目の参考ポイントより高い状態で、最初の2つの基準点の最小値に基づいてチャネルが作られるなら、そのチャネルの傾きは調整され、その方向は上方向のままでしょう。

形成されたフラクタルのバーの最小値もまた、2番目の参考ポイントより低くある場合、チャネル方向は下方向のままでしょう。. 同じことが売りポジションにも言えます。可能な方法においてのみですが。以下はここで提案したエキスパートアドバイザーを使ったトレード例です。

オーダーオープンとポジショントラッキングブロックにおいて、デモモードでテストされたポジションオープンとクローズ条件の例を見つけることができます。テスト結果:

完全なプログラムコードを以下に紹介します。:

//+------------------------------------------------------------------+
//|                                             Expert_Ch_v83_2_.mq4 |
//|                                            2009, author - Genkov |
//|                                                     Genkov@bk.ru |
//+------------------------------------------------------------------+
#property copyright "2009, author - Genkov"
#property link      "Genkov@bk.ru"
//+------------------------------------------------------------------+
extern double SL_B=200;
extern double TP_B=50;
extern double SL_S=200;
extern double TP_S=50;
extern double Lots=1.0;
double TrailingStop=40;
int Magic,i;
extern int AllB=240;        // 計算するバーの本数
int TestBar=0;              //テストされたバーのインデックス
double RatePr=0;            // 値の変化レート-ぴっぷす/バー
int NB1=-1,NB2=-1,NB3,NB5;  // 基準点の数
int Extrem=0;               // 極値のポイントインデックス: 
/* Extrem = (0)  - フラクタルは発見されない 
     Extrem = (1) - 上部のフラクタルが発見される(正の数)
     Extrem = (-1) - 下部のフラクタルが発見される(負の数)
  */
double Pr1=0,Pr2=0,Pr3,Pr5,// フラクタルと基準バーの値
Tk1,Tk2,Tk3,Tk4,Tk5; // チャネルラインを描画するための参考ポイントの値 
double space;               // 値から「弓(arrow)」までの距離
double TLUp_[10],TLDn_[10],// チャネル境界の変数
Med_[10];
int B_F=0;                  //1区間のフラクタルのバーの本数
datetime Tm1,Tm2,Tm3,Tm5;   //参考ポイントのバーの時間
string SH;                  //チャネルの傾き
bool FraktUp=false;         // 上部フラクタルをマークするフラッグ
bool FraktDn=false;         //下部フラクタルをマークするフラッグ
int q,w;
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
void DelObj1()
  {
   ObjectDelete("Tr1");
   ObjectDelete("Tr2");
   ObjectDelete("Med");
  }
//+------------------------------------------------------------------+
void Op_Sell_Ch()
  {
   if(!OrderSend(Symbol(),OP_SELL,Lots,Bid,2,Ask+SL_S*Point,Bid-TP_S*Point," ",Magic,0,Red))
     { Print("  Error when opening a SELL order  # ",GetLastError()); }
   return(0);
  }
//+------------------------------------------------------------------+
void Op_Buy_Ch()
  {
   if(!OrderSend(Symbol(),OP_BUY,Lots,Ask,2,Bid-SL_B*Point,Ask+TP_B*Point," ",Magic,0,Blue))
     { Print("  Error when opening a SELL order  # ",GetLastError()); }
   return(0);
  }
//+------------------------------------------------------------------+
void Close_B_lot()
  {
   if(!OrderClose(OrderTicket(),OrderLots(),Bid,2,HotPink)) // 0.1ロットをクローズ 
     {
      Print(" Closed order #= ",OrderTicket(),"Error #= ",GetLastError());
      RefreshRates();
     }
  }
//+------------------------------------------------------------------+
void Close_S_lot()
  {
   if(!OrderClose(OrderTicket(),OrderLots(),Ask,2,Aqua)) // 0.1ロットをクローズ 
     {
      Print(" Closed order #= ",OrderTicket(),"Error #= ",GetLastError());
      RefreshRates();
     }
  }
// ===================================================================+
int start()
  {
   int StopLevel=MarketInfo(Symbol(),MODE_STOPLEVEL);
// 区間ごとフラクタルを検索するためのバーの本数    
   switch(Period())
     {
      case 1:     B_F=12; space=0.0002; break;
      case 5:     B_F=48; space=0.0003; break;
      case 15:    B_F=24; space=0.0004; break;
      case 30:    B_F=24; space=0.0004; break;
      case 60:    B_F=12; space=0.0007; break;
      case 240:   B_F=15; space=0.0012; break;
      case 1440:  B_F=10; space=0.0030; break;
      case 10080: B_F=6;  space=0.0040; break;
     }
// ====================================================================================+
// チャネルを作成:
//「フラクタルを見つける」ことができるように3番目のバー(「0」とカウント)からカウント
   TestBar=2;  // テストされたバーの本数
   NB1=-1; NB2=-1; Extrem=0;   // バーの本数と極値が決まっていないものと仮定 
   while(((NB1==-1) || (NB2==-1)) && (TestBar<AllB))
     {//w1
      // -------------------------------------------------------------------------------+
      // もし極値が(1)より小さい(2つのオプション値は "0" と"-1"), 
      //  最小値の値の指標が考慮中のバーの指標と同時に起こると仮定
      // -------------------------------------------------------------------------------+   
      if((Extrem<1) && (TestBar==iLowest(Symbol(),Period(),MODE_LOW,B_F*2+1,TestBar-B_F)))
        {//w2
         // この瞬間に極値が存在しない時"0"
         if(Extrem==0)
           {//w3
            // 割り当て:(-1)の値を見つかった極値のポイントに割り当てる。  
            // これを低い極値とする。; 数を特定したバー(NB1)と値の変数(Pr1)に割り当てる   
            Extrem=-1; NB1=TestBar; Pr1=Low[NB1];
           }//-w3
         else  if(Extrem!=0) //1番目のポイントが先に見つかった場合
                             // さもなくな数と値の変数にポイント2を割り当てる
           {//w4
            NB2=TestBar; Pr2=Low[NB2];
           }//-w4
         // コントロールのため、値はプリントされる- Print("   bar #= ",NB2," price value= ",Pr2); 
        }//-w2
      // -------------------------------------------------------------------------------+
      //  もし極値が(-1)より大きい(オプション値は "0" と"-")ならば、
      //  最大値の値の指標が考慮中のバーのインデックスと同時に起こると仮-(上記と似た場合)
      // -------------------------------------------------------------------------------+
      if((Extrem>-1) && (TestBar==iHighest(Symbol(),Period(),MODE_HIGH,B_F*2+1,TestBar-B_F)))
        {//w5
         // if Extrem==0 
         if(Extrem==0)
           {//w6
            // バー番号(NB1)と値の変数(Pr1)をストア
            Extrem=1; NB1=TestBar; Pr1=High[NB1];
           }//-w6
         else //// さもなくな数と値の変数にポイント2を割り当てる
           {//w7
            NB2=TestBar; Pr2=High[NB2];
           }//-w7
        }//-w5
      TestBar++;
     }//-w1
// -----------------------------------------------------------------------------------+
   if((NB1==-1) || (NB2==-1)) //  直近の AllB バーで基準点が見当たらない
     {
      DelObj1(); ObjectDelete("Cross1"); ObjectDelete("Cross2");  ObjectDelete("Rep1");
      ObjectDelete("Rep2"); ObjectDelete("Rep3"); ObjectDelete("Rep5");
      // Print(" === > チャネルのためのバーはありません "); // コントロールのためのみ(削除できます)
      return(-1);
     }
// --------------------------------- 
// プライスチェンジのレートを計算
   RatePr=(Pr2-Pr1)/(NB2-NB1);
//もし変数が正の数なら、下降チャネルとして扱う。そうでなければ上昇
   if(RatePr>0) SH="downward"; else  SH="upward";
// チャネルラインのため基準点の時間を特定
   Tm1=Time[0];    Tm2=Time[NB2+50];
// **************************************************************************************   
   if(Extrem==1) // もし極大値が最初に見つかった場合
     {//1(Extrem=1)
      // 2つの基準点とプライスチェンジのレートが利用可能なら
      // このラインの参考ポイントを特定:
      // 最初の参考ポイントは 「0」バーの基準点の射影
      double Tk1=Pr1-NB1*RatePr;
      // 2番目の参考ポイントは チャートの左側の射影
      double Tk2=Tk1+(NB2+50)*RatePr;
      反対側のチャネルラインを特定したラインと並行にプロット
      //反対側のチャネルラインの基準点を探す: 
      // 検索の出発点として2番目のバーの最小値をとる
      Tk3=Low[2]-2*RatePr; // "0"バーに2番目のバーを置換
      for(i=3;i<=NB2;i++) // 3番目のバーから検索をスタート  
        {//2(1)Up
         if(Low[i]<Tk3+i*RatePr) // "0" バーに置換した値の最小値を使用
           {//3(1)Up
            Tk3=Low[i]-i*RatePr; // 3番目の参考ポイント("0" バーの置換)
            Pr5=Low[i];          //下部のチャネルラインのための3番目基準点
            NB5=i;               // 3番目基準点のバーの数
           }//-3(1)Up
        }//-2(1)Up
      //最初の2本のバーを見てみましょう: 「0」と「1」; それらの最小値は2番目のバーより小さくなるかもしれません。
      //もしこれら2本のバーを使ってチャネルの調整をおこなうならば、 
      //チャネルは下降の値動き方向へ広がるようになるでしょう。;もしこれが無視されたら、 
      //下降の値動きはチャネルライン・ブレイクアウトとみなされます(トレンドの始まりの可能性がある!)
      // if(Low[0]<Tk3) {Tk3=Low[0]; Pr5=Low[0]; NB5=0;}
      // if(Low[1]<Tk3+RatePr) {Tk3=Tk3+RatePr; Pr5=Low[1]; NB5=1;}
      datetime TmR1=Time[NB1];    datetime TmR2=Time[NB2];   datetime TmR5=Time[NB5];
      // -------------------------------------------------------------------------------------
      //以下のオペレータはプログラムパフォーマンスのビジュアルコントロールのみのためのものです(削除できます)
      //チャネル傾きの値、スピードレート、Extrem=1における基準点の数と時間
      string TNB1=TimeToStr(TmR1,TIME_DATE|TIME_MINUTES);
      string TNB2=TimeToStr(TmR2,TIME_DATE|TIME_MINUTES);
      string TNB5=TimeToStr(TmR5,TIME_DATE|TIME_MINUTES);
      //   Print(" channel- ",SH," ; speed = ",DoubleToStr(NormalizeDouble(RatePr,8),8),
      //         " pip / bar"," ; Extrem= ",Extrem);
      //   Print(" NB2= ",NB2," ; time= ",TNB2," ; NB5= ",NB5,
      //         " ; time= ",TNB5," ; NB1= ",NB1," ; time= ",TNB1);
      // --------------------------------------------------------------------------------------
      //プログラムパフォーマンスの明示のため、チャート上のチャネルラインに基準点をマーク
      ObjectDelete("Rep1"); ObjectDelete("Rep2"); ObjectDelete("Rep3"); ObjectDelete("Rep5");
      ObjectCreate("Rep1",OBJ_ARROW,0,TmR1,Pr1+2*space);
      ObjectSet("Rep1",OBJPROP_COLOR,Yellow);
      ObjectSet("Rep1",OBJPROP_ARROWCODE,72);
      ObjectCreate("Rep2",OBJ_ARROW,0,TmR2,Pr2+2*space);
      ObjectSet("Rep2",OBJPROP_COLOR,Yellow);
      ObjectSet("Rep2",OBJPROP_ARROWCODE,72);
      ObjectCreate("Rep5",OBJ_ARROW,0,TmR5,Pr5-space);
      ObjectSet("Rep5",OBJPROP_COLOR,Yellow);
      ObjectSet("Rep5",OBJPROP_ARROWCODE,71);
      ObjectDelete("Cross2");
      // -------------------------------------------------------------------------------------
      //下部のチャネル境界における参考ポイントの座標を求めるため値を計算:
      double Tk3=Pr5-RatePr*NB5; //「0」ポイントにおける下部チャネル境界の値
      double Tk4=Tk3+RatePr*(NB2+50);// チャートの左側における下部のチャネル境界の値
     }//- 1(Extrem=1)
// ******************************************************************************************
   else  if(Extrem==-1)//もし極小値が最初に見つかった場合
     {//1(Extrem= -1)
                                     //下部のチャネル境界における参考ポイントの値:
      Tk3=Pr1-NB1*RatePr;      // 「0」ポイント
      Tk4=Tk3+(NB2+50)*RatePr; //左側のポイント
                               反対側のチャネルラインを特定したラインと並行にプロット
      //反対側のチャネルラインの基準点を探す 
      // 検索の出発点として2番目のバーの値をとる
      Tk1=High[2]-2*RatePr; //「0」バーに2番目のバーを射影 
      for(i=3;i<=NB2;i++) //3番目のバーから検索をスタート
        {//2(-1)
         if(High[i]>Tk1+i*RatePr)
           {//3(-1)
            Tk1=High[i]-i*RatePr; //3番目の参考ポイント("0" バーの射影)
            Pr3=High[i];          上部のチャネルラインのための3番目基準点
            NB3=i;                //3番目の基準点のバーの本数
           }//-3(-1)
         //最初の2本のバーを見てみましょう: 「0」と「1」
         // if(High[0]>Tk1) {Tk1=High[0]; Pr3=High[0]; NB3=0;}
         // if(High[1]>Tk1+RatePr) {Tk1=Tk1+RatePr; Pr3=High[1]; NB3=1;}
         TmR1=Time[NB1];    TmR2=Time[NB2];   datetime TmR3=Time[NB3];
        }//- 2(-1)
      // ---------------------------------------------------------------------------------
      //パフォーマンス結果をモニターするため以下のオペレータを加えます。 
      //(これらはプログラムパフォーマンスに影響しないので削除できます)
      //チャネル(スピード)の傾きの値、スピードレート、 
      //Extrem=1における基準点の数と時間を表示
      // TNB1=TimeToStr(TmR1,TIME_DATE|TIME_MINUTES);  
      // TNB2=TimeToStr(TmR2,TIME_DATE|TIME_MINUTES);
      // string TNB3=TimeToStr(TmR3,TIME_DATE|TIME_MINUTES);
      // Print(" channel- ",SH," ; price speed rate= ",DoubleToStr(NormalizeDouble(RatePr,8),8),
      //       " pip / bar"," ; Extrem= ",Extrem);
      // Print(" ; NB2= ",NB2," ; time= ",TNB2," ; NB3= ",NB3,
      //       " ; time= ",TNB3," ; NB1= ",NB1," ; time= ",TNB1);
      // ----------------------------------------------------------------------------------
      //明示のため、チャート上のチャネルラインに基準点をマーク
      ObjectDelete("Rep1"); ObjectDelete("Rep2");
      ObjectDelete("Rep3"); ObjectDelete("Rep5");
      ObjectCreate("Rep1",OBJ_ARROW,0,TmR1,Pr1-space);
      ObjectSet("Rep1",OBJPROP_COLOR,Yellow);
      ObjectSet("Rep1",OBJPROP_ARROWCODE,71);
      ObjectCreate("Rep2",OBJ_ARROW,0,TmR2,Pr2-space);
      ObjectSet("Rep2",OBJPROP_COLOR,Yellow);
      ObjectSet("Rep2",OBJPROP_ARROWCODE,71);
      ObjectCreate("Rep3",OBJ_ARROW,0,TmR3,Pr3+2*space);
      ObjectSet("Rep3",OBJPROP_COLOR,Yellow);
      ObjectSet("Rep3",OBJPROP_ARROWCODE,72);
      ObjectDelete("Cross1");
      // ---------------------------------------------------------------------------------    
      //上部チャネル境界における参考ポイントの座標を求めるため値を計算:
      Tk1=Pr3-RatePr*NB3; //「0」ポイントにおける上部チャネル境界の値
      Tk2=Tk1+RatePr*(NB2+50);// 左側ポイントにおける上部チャネル境界の値
     }//-1(Extrem= -1)
// ---------------------------------======================================================
//直近6本のバーでチャネルとチャネルとの境界の中間値を計算
   for(int i=0;i<6;i++)
     {
      TLUp_[i]=Tk1+i*RatePr;
      TLDn_[i]=Tk3+i*RatePr;
      Med_[i]=(TLUp_[i]+TLDn_[i])/2;
     }
// --------------------------------------------------------------------
//もし値が上部チャネルラインをクロスしたら、アスタリスクでマークし効果音通知を加えます。:
   if(Bid>TLUp_[0])
     {
      bool TrUp=true; //bool TrDn=false; 
      ObjectDelete("Cross1");  ObjectDelete("Cross2");
      ObjectCreate("Cross1",OBJ_ARROW,0,Tm1,High[1]+2*space);
      ObjectSet("Cross1",OBJPROP_COLOR,DeepPink);
      ObjectSet("Cross1",OBJPROP_ARROWCODE,171);
      PlaySound("alert.wav"); // ファイルはテーミナルディレクトリ\soundsの下位に保存しなければいけません
     }
//もし値が下部部チャネルラインをクロスしたら、アスタリスクでマークし効果音通知を加えます。
   if(Bid<TLDn_[0])
     {
      ObjectDelete("Cross2");  ObjectDelete("Cross1");
      /// Print("下部チャネルラインのクロスオーバーがありました");
      ObjectCreate("Cross2",OBJ_ARROW,0,Tm1,Low[1]-space);
      ObjectSet("Cross2",OBJPROP_COLOR,DodgerBlue);
      ObjectSet("Cross2",OBJPROP_ARROWCODE,171);
      PlaySound("alert.wav"); // ファイルはテーミナルディレクトリ\soundsの下位に保存しなければいけません 
     }
// ------------------------------------------------------------------------------------- 
//チャート上にチャネル境界をプロット、前もって存在している基準点は削除
   DelObj1();
   ObjectCreate("Tr1",OBJ_TREND,0,Tm2,Tk2,Tm1,Tk1);
   ObjectSet("Tr1",OBJPROP_COLOR,Lime);
   ObjectSet("Tr1",OBJPROP_WIDTH,1); //2
   ObjectSet("Tr1",OBJPROP_STYLE,STYLE_SOLID);
   ObjectCreate("Tr2",OBJ_TREND,0,Tm2,Tk4,Tm1,Tk3);
   ObjectSet("Tr2",OBJPROP_COLOR,Lime);
   ObjectSet("Tr2",OBJPROP_WIDTH,1); //2
   ObjectSet("Tr2",OBJPROP_STYLE,STYLE_SOLID);
   ObjectCreate("Med",OBJ_TREND,0,Tm2,(Tk2+Tk4)/2,Tm1,(Tk1+Tk3)/2);
   ObjectSet("Med",OBJPROP_COLOR,Lime);
   ObjectSet("Med",OBJPROP_WIDTH,1);
   ObjectSet("Med",OBJPROP_STYLE,STYLE_DOT);
// ---- チャートにフラクタルをマークするブロック ---------------------------------
   if((High[2]>High[1] && Bid<High[2] && High[2]>High[3] && High[2]>High[4]) || 
      (High[2]==High[1] && Bid<High[1] && High[2]>High[3] && High[2]>High[4]))
     {
      double FraktalUp=High[2]; //上部のフラクタル
      double FraktalDn=0;
      //フラクタルが形成され、このフラクタルが新しい基準点の原因
      //であったならば-値によって上部のチャネルラインのクロスオーバーのマークを削除
      if(High[2]>=TLUp_[i]) ObjectDelete("Cross1");
      ObjectDelete("Fraktal"+(q-1));  //ObjectDelete("Frakt"+(w-1));
      ObjectCreate("Fraktal"+q,OBJ_ARROW,0,Time[2],High[2]+2*space+0.0002);
      ObjectSet("Fraktal"+q,OBJPROP_COLOR,Orchid);
      ObjectSet("Fraktal"+q,OBJPROP_ARROWCODE,217);
      bool FraktUp=true; //bool FraktDn=false;//これはトレードに有効です
      q++;
     }
   if((Low[2]<Low[1] && Bid>Low[2] && Low[2]<Low[3] && Low[2]<Low[4]) || 
      (Low[2]==Low[1] && Bid>Low[1] && Low[2]<Low[3] && Low[2]<Low[4]))
     {
      FraktalDn=Low[2]; // 下部フラクタル 
      FraktalUp=0;
      if(Low[2]>=TLUp_[i]) ObjectDelete("Cross2");
      ObjectDelete("Frakt"+(w-1)); //ObjectDelete("Fraktal"+(q-1));
      ObjectCreate("Frakt"+w,OBJ_ARROW,0,Time[2],Low[2]-2*space);
      ObjectSet("Frakt"+w,OBJPROP_COLOR,Orchid);
      ObjectSet("Frakt"+w,OBJPROP_ARROWCODE,218);
      FraktDn=true; FraktUp=false;
      w++;
     }
// ---------------------------------------------------------------+
// ポジションオープン条件のブロック。   これは例にすぎません。  +
//実際の使用を推奨しているとは思わないでください!+          
// ---------------------------------------------------------------+
   if(OrdersTotal()<1) // 1ポジションをオープン  
     {
      // - 16- SELL ---
      if(Extrem==1 && //2つの上部基準点
         RatePr>0 && //下降方向のチャネル
         (Tk1-Tk3)>20*Point && //チャネルサイズ > 20pip 
         Bid<High[1] && // 値は前のバーより小さい
         (TLUp_[1]-High[1])<3*Point) //最初のバーは下部のチャネルラインから3ピップス以内
        {
         Print(" Open - 16-SELL === ");
         //   SL_S=50;
         //   if(SL_S<StopLevel) SL_S=StopLevel;
         //   TP_S=80; 
         Op_Sell_Ch();
         return(0);
        }
      // - 18- BUY ---
      if(Extrem==-1 && // 2つの下部基準点
         RatePr<0 && // 上昇方向のチャネル
         (Tk1-Tk3)>20*Point && //チャネルサイズ > 20pip 
         Bid>Low[1] && //値が前のバーより大きい
         (Low[1]-TLDn_[1])<3*Point) //最初のバーは下部のチャネルラインから3ピップス以内
        {
         Print(" Open - 18-BUY === ");
         //    SL_B=50;
         //    if(SL_B<StopLevel) SL_B=StopLevel;
         //    TP_B=80; 
         Op_Buy_Ch();
         return(0);
        }
     }
//------------------------------------------------------------------------+
// 売りポジションのオープンをトラッキング                                    |
//+=======================================================================+
   for(i=OrdersTotal()-1;i>=0;i--) //売りオーダーセレクションループ処理
     {//1-ポジションセレクションループ処理
      if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {Print("オーダーセレクションエラー = ",GetLastError()); }
      if(OrderType()==OP_SELL) //オープン売りオーダーがある場合
        { //2-type_Sell
         if((FraktalDn<=TLDn_[2] || 
            Low[2]<=TLDn_[2]) && 
            (Bid>Low[1] && Low[1]<=TLDn_[1]) && 
            (OrderOpenPrice()-Bid)*Point>0) // ロスではありません!
           {//5
            Print(" 下部チャネルラインでクローズ ");
            Close_S_lot();
            //チャネルが上昇方向の場合 
            if(RatePr<0)
              {
               Print(" 買いポジションをオープン ");
               Op_Buy_Ch();
              }
           }//-5
        }//-2 type_Sell
      //------------------------------------------------------------------------+
      // 買いポジションのオープンをトラッキング                       |
      //+=======================================================================+
      else
      if(OrderType()==OP_BUY) //オープン買いオーダーがある場合
        { //4-type_Buy
         if((FraktalUp>=TLUp_[2] || 
            High[2]>=TLUp_[2]) && 
            //下部の基準点をもとにチャネルが形成され上昇方向の場合 
            //値が上部境界を越え、  下降しようとしている場合 
            //上部チャネルラインにおいてバー「1」はバー「0」より大きくバー「2」より大きかった場合 
            //これは上部フラクタルフォーメーションのようにみえチャネルサイズは大きくなります。 
            //同時刻、ストキャスティクスは80以上です。
            //そして下がり始めシグナルラインを越えます。 
            //値が下降する可能性が高くフォーメーションを完全に形成するバー「0」を 
            //予想するべきではありません。したげって買いポジションをクローズします。
            (Bid<High[1] && High[1]>=TLUp_[1]) && 
            (Ask-OrderOpenPrice())*Point>0) // ロスではない!
           {//5
            Print(" 上部チャネルラインでクローズ ");
            Close_B_lot();
            //チャネルが下降方向の場合 
            if(RatePr>0)
              {
               Print(" 売りポジションをオープン ");
               Op_Sell_Ch();
              }
           }//-5
        }//-4-type_Buy
     }//-1-ポジションセレクションループ処理
//----------------
   return(0);
  }
//+------------------------------------------------------------------+


まとめ

チャネルトレードの可能性に関する疑問は十分に回答されたと信じています。エキスパートアドバイザーをより改良できるクリティカルなフィードバックを楽しみにしています。私の経験が初心者トレーダーだけでなく有用なものであることを願っております。

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1375

インディケータとシグナルの利益性のビジュアルテスト インディケータとシグナルの利益性のビジュアルテスト
取引シグナルのインディケータの選択や、それらの計算方法は、通常、これらのシグナルを使用するエキスパートアドバイザのバックテストを行い分析します。しかし、各インディケータに基づいてエキスパートアドバイザを作成するのは、常に可能で必要で妥当であるわけではありません。他のインディケータのシグナルでの、取引の利益性の能率的な計算は、自分でそれらのシグナルを集め、それに基づく理想的な取引の図を描く、特別なインディケータを使う事で行う事ができます。これを使う事で、視覚的に結果を評価するだけでなく、素早く最適なパラメータを選出することができます。
Lite_EXPERT2.mqhファイル - EAの最適化の実践例 Lite_EXPERT2.mqhファイル - EAの最適化の実践例
この記事では、筆者はEA構築の具体例にて、Lite_EXPERT2.mqhファイルの関数の紹介を続けます。Average True Range (ATR)の指標値に基づいて明確にされる取引から取引へと変動する指値注文の使用案を検証します。
テクニカル指標や取引シグナルの利益表のビジュアル最適化 テクニカル指標や取引シグナルの利益表のビジュアル最適化
この記事は、前の記事「テクニカル指標とアラートの利益のビジュアルテスト」の関連記事です。パラメータ変更プロセスに双方向性を加え、検査の目的を変えることにより、シグナルを用いて取引結果予想を表示するだけでなく、メインチャートのシグナルパラメータ値を制御する役割として仮想スライドを動かすことで、取引レイアウトやバランスチャート、取引結果を即座に取得できるツールを作成します。
Lite_EXPERT2.mqh:エキスパートアドバイザー開発者のためのファンクションキット Lite_EXPERT2.mqh:エキスパートアドバイザー開発者のためのファンクションキット
本稿は「ポピュラーなトレードシステムに基づくエキスパートアドバイザーとトレーディングロボット最適化の錬金術」シリーズの続きです。読者はLite_EXPERT2.mqh fileのより多くの普遍的な関数ライブラリについて親しくなるでしょう。