English Русский 中文 Español Deutsch Português
インディケータとシグナルの利益性のビジュアルテスト

インディケータとシグナルの利益性のビジュアルテスト

MetaTrader 4 | 5 11月 2015, 09:32
610 0
Sergey Kravchuk
Sergey Kravchuk

取引シグナルのインディケータの選択や、それらの計算方法は、通常、これらのシグナルを使用するエキスパートアドバイザのバックテストを行い分析します。しかし、各インディケータに基づいてエキスパートアドバイザを作成するのは、常に可能で必要で妥当であるわけではありません。他のインディケータのシグナルでの、取引の利益性の能率的な計算は、自分でそれらのシグナルを集め、それに基づく理想的な取引の図を描く、特別なインディケータを使う事で行う事ができます。これを使う事で、視覚的に結果を評価するだけでなく、素早く最適なパラメータを選出することができます。

思いがけなく手元に差し出された、またはずっと前にやっと探し出したインディケータを見ながら、このシグナルによる取引の結果は、どのようなものになるかすぐにでも知りたいと何度思ったでしょうか。また、まだそれに基づくエキスパートアドバイザも、インディケータもない新しい取引システムを提供された時にも、素早く評価を行いたいと思うものです。重大な仕事に取り掛かり、エキスパートアドバイザの作成を始める前に、それが意味を成すものかどうか、概算でもいいからしたくなります。

もしくは、良いシグナルを持つインディケータはあるけど、そのパラメータは最適なものではなく、より良く改善できると感じていて、しかもあなたはどこでどうそれを行うかを思い浮かべることができるといった状況です。どうしたら、長く難しいプログラミングに縛られる事なく、素早く自分のアイディアを検証することができるでしょうか?

問題提起

では、私達には何があり、何を求めているのかを考えてみましょう。例として、皆さんがご存知のMetaTrader 4のスタンダードパックのZigZagを見てみましょう。これを任意の時間軸の任意の通過ペアに当てて、本当に取引をしたいか?全ては分かりやすく、上の折り目で売り、下の折り目で売りを閉じて買いを行う必要があります。

ここで質問です。このような取引はどれくらいの利益をもたらしますか?これに対する答えは簡単に得ることができます。全ての部分の高さを合計し、取引ロットとデポジットの通貨の1ポイントの価格を含めて再計算します。iCustom関数を呼び出すことで、ジグザグの値のバッファにアクセスすることができます。

P=iCustom(NULL,0,"ZigZag",0,i); 

i は、値を取得する必要があるバーの番号。

残るは、バッファの全ての値を取得し、ジグザグが構築されるゼロの値を持つ全てのポイントを探しだし、セグメントの高さを合計します。見やすくする為に、これらの線を描いて、さらに操作や利益性に応じて着色することもできます。課題は難しいものではなく、これをインディケータに任せることができます。

全般的解答

このようなインディケータが任意のインディケータをテストする事ができるように、その普遍性を確保する必要があります。あらゆるインディケータや取引システムは、一般的に、買い、売り、買い決済、売り決済の4つの操作のみを想定しています。私達のインディケータでは、これらのうちの一つ一つに任意のソースから記入することができる別個の配列を備える必要があります。シグナルの配列を埋めるコードを記入し、自分自身で編集する必要がある唯一のものです。(パラメータのうちのいくつかは、外部変数にも編集を加える必要があるかもしれません)

機能的に、インディケータは次のブロックから構成されています。

  • 初期化ブロック - ここではシグナルの配列のメモリを割り当て、カウンターをリセットします。
  • シグナル配列の記入ブロック - こちらでは、シグナル計算の異なるアルゴリズムを書きつつ、または他のインディケータからシグナルを受け取りつつ、コードを変更します。
  • 重複シグナルのクリアブロック– このブロックは、一つのシグナルを生成する不連続モードで動作するのではなく、それによってオーダーが開かれる一番最初のシグナルの発生時ではなく、インディケータがオープンの為の条件の有無を確定した時、連続モードで動作するインディケータからのシグナルの間引きの為に必要なものです。ブロックでは次のメカニズムが実装されています。もし二つの同じシグナルが隣同士のバーにある時、私達は一つのオーダーのみ使用し、それはすでに次のバー(左の)で開かれているとみなすので、右のものは破棄します。ここでは、設定したパラメータの日付の範囲外にあるシグナルからのクリアが行われます。
  • オープンとクローズマークの配置ブロック - このブロックでは、間引かれた(不連続の)シグナルによってジグザグが描かれ、必要に応じてシグナルと他のインディケータのチャート(シグナルのソースチャートを含む)との同期化を観察することができる垂直線が配置されます。
  • 配置されたマークによる計算結果ブロック - マーク配置の動きによって、開かれた注文の数とその利益が計算されます。このブロックはいくつかの追加の計算を行い、それらの結果をチャートのメインウィンドウにコメントで表示します。
  • 補助機能ブロック- ここには二つの機能が配置されています。マーキングの垂直線の配置とジグザグの一部の描画です。

実装

ZigZagインディケータからのデータ記入の例を含むインディケータのコードです。

/*///———————————————————————————————————————————————————————————————————————————————————————————————————————
 
    IndicatorTester.mq4 
  
    インディケータとシグナルの利益性のビジュアルテスト
    
    Copyright © 2006, Кравчук Сергей,  http://forextools.com.ua
 
/*///———————————————————————————————————————————————————————————————————————————————————————————————————————
#property copyright "Copyright © 2006-2008, Sergey Kravchuk. http://forextools.com.ua"
#property link      "http://forextools.com.ua"
 
#property indicator_chart_window
#property indicator_buffers 0
 
// チャートエレメントの表示パラメータ
extern bool   ShowZZ          = true;           // 33を描くか
extern bool   ShowMARKERS     = true;           // 垂直のマーカーラインを描くか
 
//チャート作成日
extern datetime DateStart     = D'1.01.1970';
extern datetime DateEnd       = D'31.12.2037';
 
//利益計算のパラメータ
extern double LotForCalc      = 0.05;           // 利益計算の為のロットサイズ
extern int    Optimizm        = 0;              // -1は悲観的な計算で、0はバーの始値
                                                //+1は楽観的計算
 
// 買いのラインの色
extern color  ColorProfitBuy  = Blue;           // 利益のある買いのラインの色
extern color  ColorLossBuy    = Red;            // 損失のある買いのラインの色
extern color  ColorZeroBuy    = Gray;           // 利益ゼロの買いのラインの色
 
// 売りのラインの色
extern color  ColorProfitSell = Blue;           // 利益のある売りのラインの色
extern color  ColorLossSell   = Red;            // 損失のある売りのラインの色
extern color  ColorZeroSell   = Gray;           // 利益ゼロの売りのラインの色
 
// シグナルラインの色
extern color  ColorBuy        = CornflowerBlue; // 買いシグナルラインの色
extern color  ColorSell       = HotPink;        // 売りシグナルのラインの色
extern color  ColorClose      = Gainsboro;      // クローズシグナルのラインの色
 
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
double sBuy[],sCloseBuy[],sSell[],sCloseSell[]; // シグナル配列
int sBuyCnt,sSellCnt,sBuyCloseCnt,sSellCloseCnt;// シグナルカウンター 
int i,DisplayBars;
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
// サービスコード
#define MrakerPrefix "IT_"
#define OP_CLOSE_BUY  444
#define OP_CLOSE_SELL 555
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
int init()   { ClearMarkers(); return(0); }
int deinit() { ClearMarkers(); return(0); }
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
int start() 
{ 
  double Profit=0,P1,P2; int CntProfit=0,CntLoose=0,i1,i2;
 
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // インディケータが再描画される場合に、すべてのマークが削除されます
  ClearMarkers(); 
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // シグナルカウンターを準備します
  sBuyCnt=0; sSellCnt=0; sBuyCloseCnt=0; sSellCloseCnt=0; 
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // シグナル配列にメモリを割り当て、それらの数値をゼロにします
  DisplayBars=Bars; // 表示されるバーの数
  ArrayResize(sBuy,DisplayBars);  ArrayInitialize(sBuy,0);
  ArrayResize(sSell,DisplayBars); ArrayInitialize(sSell,0);
  ArrayResize(sCloseBuy,DisplayBars);  ArrayInitialize(sCloseBuy,0);
  ArrayResize(sCloseSell,DisplayBars); ArrayInitialize(sCloseSell,0);
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // 初めのポイントを見つけ、その位置と価格を記憶します
  for(i1=Bars-1;i1>=0;i1--) { P1=iCustom(NULL,0,"ZigZag",0,i1); if(P1!=0) break; }
  // ジグザグのポイントを修正します
  for(i2=i1-1;i2>=0;i2--) 
  {
    // 次のポイントを見つけ、その位置と価格を記憶します
    for(i2=i2;i2>=0;i2--) { P2=iCustom(NULL,0,"ZigZag",0,i2); if(P2!=0) break; }
    
    if(i2<0) break; // 最後のポイントを現在の価格に設けます
 
    // オープンの条件は同時、反対の注文のクローズの条件
    if(P1>P2) { sSell[i1]=1; sBuy[i2]=1; sCloseSell[i2]=1; }
    if(P1<P2) { sBuy[i1]=1; sSell[i2]=1; sCloseBuy[i2]=1; }
 
    P1=P2; i1=i2; // 発見したポイントのバーを記憶する
  }
    //——————————————————————————————————————————————————————————————————————————————————————————————————————
  // チャートの左側の一番最初のもののみを残し、重複するシグナルを削除します
  for(i=0;i<DisplayBars;i++) 
  {
    if(sBuy[i]==sBuy[i+1]) sBuy[i]=0;
    if(sSell[i]==sSell[i+1]) sSell[i]=0;
    if(sCloseBuy[i]==sCloseBuy[i+1]) sCloseBuy[i]=0;
    if(sCloseSell[i]==sCloseSell[i+1]) sCloseSell[i]=0;
  }
  // 指定した日付の範囲外のシグナルを削除します
  for(i=0;i<DisplayBars;i++) 
  {
    if(Time[i]<DateStart || DateEnd<Time[i]) { sBuy[i]=0; sSell[i]=0; sCloseBuy[i]=0; sCloseSell[i]=0; }
  }
  // 範囲の境界線上で強制終了を追加します
  if(DateEnd<=Time[0]) { i=iBarShift(Symbol(),Period(),DateEnd); sBuy[i]=0; sSell[i]=0; 
                                                             sCloseBuy[i]=1; sCloseSell[i]=1; }
  if(DateEnd >Time[0]) { sCloseBuy[0]=1; sCloseSell[0]=1; }
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // シグナルの数を数える
  for(i=0;i<DisplayBars;i++) 
  {
    if(sBuy [i]!=0) sBuyCnt++;  if(sCloseBuy [i]!=0) sBuyCloseCnt++;
    if(sSell[i]!=0) sSellCnt++; if(sCloseSell[i]!=0) sSellCloseCnt++;
  }
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // マークを配置し、33を描き、利益を計算します
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // 買いを処理します
  for(i=DisplayBars-1;i>=0;i--) // ポイントを集めます
  {
    // 次のオープンポイントを見つけ、その位置と価格を記憶します
    for(i1=i;i1>=0;i1--) if(sBuy[i1]!=0) break; 
 
    // 次のクローズポイントを見つけ、その位置と価格を記憶します
    for(i2=i1-1;i2>=0;i2--) if(sCloseBuy[i2]!=0) break;
    if(i2<0) i2=0; // 最後の閉じていないポジションは現在の価格でクローズを算出します 
    i=i2; // オープンポイント検索続行の為の新しいバー
 
    // Optimizmパラメータによる描画の為の価格を定義します
    if(Optimizm<0)  { P1=High[i1]; P2=Low[i2];  } 
    if(Optimizm==0) { P1=Open[i1]; P2=Open[i2]; } 
    if(Optimizm>0)  { P1=Low[i1];  P2=High[i2]; } 
    
    P1/=Point; P2/=Point; // 価格をポイントにします
    
    // 利益を定義し、適切なバッファに記入します
    if(i1>=0) 
    { 
      Profit=Profit+P2-P1; // 合計利益を収集します
      if(P2-P1>=0) CntProfit++; else CntLoose++; // 注文数を計算します
      DrawLine(i1,i2,OP_BUY,Optimizm); // 注文のラインを描画します
      PlaceMarker(i1,OP_BUY); 
      PlaceMarker(i2,OP_CLOSE_BUY); 
    }
  }
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // 売りを処理します
  for(i=DisplayBars-1;i>=0;i--) // ポイントを集めます
  {
    // 次のオープンポイントを見つけ、その位置と価格を記憶します
    for(i1=i;i1>=0;i1--) if(sSell[i1]!=0) break; 
 
    // 次のクローズポイントを見つけ、その位置と価格を記憶します
    for(i2=i1-1;i2>=0;i2--) if(sCloseSell[i2]!=0) break;
    if(i2<0) i2=0; // 最後の閉じていないポジションは現在の価格でクローズを算出します 
    i=i2; // オープンポイント検索続行の為の新しいバー
 
    // Optimizmパラメータによる描画の為の価格を定義します
    if(Optimizm<0)  { P1=Low[i1];  P2=High[i2]; } 
    if(Optimizm==0) { P1=Open[i1]; P2=Open[i2]; } 
    if(Optimizm>0)  { P1=High[i1]; P2=Low[i2];  } 
    
    P1/=Point; P2/=Point; // 価格をポイントにします
    
    // もし二つのポイントがある場合、利益を明確にし、適切なバッファに記入します
    if(i1>=0) 
    { 
      Profit=Profit+P1-P2; // 合計利益を収集します
      if(P1-P2>=0) CntProfit++; else CntLoose++; // 注文の数を計算します
      DrawLine(i1,i2,OP_SELL,Optimizm); // 注文のラインを描画します
      PlaceMarker(i1,OP_SELL); 
      PlaceMarker(i2,OP_CLOSE_SELL);
    }
  }
  //————————————————————————————————————————————————————————————————————————————————————————————————————————
  // コメントの為の最終値の計算  
  int Cnt=CntProfit+CntLoose; // 操作総数
  // ポイントの通貨ペアへの交換係数
  double ToCurrency = MarketInfo(Symbol(),MODE_TICKVALUE)*LotForCalc;    
  string msg="Период: "+TimeToStr(MathMax(DateStart,Time[Bars-1]))+" - "
                                                      + TimeToStr(MathMin(DateEnd,Time[0]))+"\n\n";
  
  msg=msg+
  sBuyCnt+"買いと"+sBuyCloseCnt+"そのクローズ数\n"+
  sSellCnt+"売りと"+sSellCloseCnt+"そのクローズ数\n\n";
  
  // 日中の合計時間
  int TotalDays = (MathMin(DateEnd,Time[0])-MathMax(DateStart,Time[Bars-1]))/60/60/24; 
                                                                       //秒を日に変換
  if(TotalDays<=0) TotalDays=1; // ゼロ除算を避けるため
  
  if(Cnt==0) msg=msg+(「操作無し 」);
  else msg=msg+
  (
    DoubleToStr(Profit,0)+"総使用時間のの" \n日"で"+Cnt+" 操作によるポイント数"+
    DoubleToStr(Profit/Cnt,1)+"操作につきポイント数("
    DoubleToStr(Profit/TotalDays,1)+" за день)\n\n"+
    +"DoubleToStr(LotForCalc,2)+"ロット取引する場合+"AccountCurrency()"で計算される値"+":\n"+
    DoubleToStr(Profit*ToCurrency,0)+"ポイント総額"+
    DoubleToStr(Profit/Cnt*ToCurrency,1)+"操作につきポイント数"(
    "DoubleToStr(Profit/TotalDays*ToCurrency,1)+日につきポイント数「\n\n」+
    CntProfit+("「+DoubleToStr(((CntProfit)*1.0/Cnt*1.0)*100.0,1)利益的な取引の数"+"%)\n"+
    CntLoose+("+DoubleToStr(((CntLoose)*1.0/Cnt*1.0)*100.0,1)損失的な取引の数"+"%)"
  );
  Comment(msg);
  
}
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
 
 
 
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
// 私達のチャートの全てのオブジェクトを削除
void ClearMarkers() 
{ 
  for(int i=0;i<ObjectsTotal();i++) 
  if(StringFind(ObjectName(i),MrakerPrefix)==0) { ObjectDelete(ObjectName(i)); i--; } 
}
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
// 垂直線の設置、op_typeの操作のマーク
void PlaceMarker(int i, int op_type)
{
  if(!ShowMARKERS) return; // マーカーの表示がオフになっています
 
  color MarkerColor; string MarkName; 
 
  // __ ソートでクローズラインがオープンラインの下に描かれるようにする為に 
  if(op_type==OP_CLOSE_SELL) { MarkerColor=ColorClose; MarkName=MrakerPrefix+"__SELL_"+i; }
  if(op_type==OP_CLOSE_BUY)  { MarkerColor=ColorClose; MarkName=MrakerPrefix+"__BUY_"+i;  }  
  if(op_type==OP_SELL)       { MarkerColor=ColorSell;  MarkName=MrakerPrefix+"_SELL_"+i;  }
  if(op_type==OP_BUY)        { MarkerColor=ColorBuy;   MarkName=MrakerPrefix+"_BUY_"+i;   }
 
  ObjectCreate(MarkName,OBJ_VLINE,0,Time[i],0); 
  ObjectSet(MarkName,OBJPROP_WIDTH,1); 
  if(op_type==OP_CLOSE_BUY || op_type==OP_CLOSE_SELL) ObjectSet(MarkName,OBJPROP_STYLE,STYLE_SOLID); 
  else ObjectSet(MarkName,OBJPROP_STYLE,STYLE_DOT);
  ObjectSet(MarkName,OBJPROP_BACK,True);  
 
  ObjectSet(MarkName,OBJPROP_COLOR,MarkerColor);
}
//——————————————————————————————————————————————————————————————————————————————————————————————————————————
// Optimizmパラメータの価格によるop_typeの操作の為のチャート上のラインの設置
void DrawLine(int i1,int i2, int op_type, int Optimizm)
{
  if(!ShowZZ) return; // 33の表示がオフになっています
  
  color СurColor;
  string MarkName=MrakerPrefix+"_"+i1+"_"+i2;
  double P1,P2;
  
  // Optimizmパラメータによる描画の為の価格を定義します
  if(Optimizm<0 && op_type==OP_BUY)  { P1=High[i1]; P2=Low[i2];  } 
  if(Optimizm<0 && op_type==OP_SELL) { P1=Low[i1];  P2=High[i2]; } 
  if(Optimizm==0)                    { P1=Open[i1]; P2=Open[i2]; } 
  if(Optimizm>0 && op_type==OP_BUY)  { P1=Low[i1];  P2=High[i2]; } 
  if(Optimizm>0 && op_type==OP_SELL) { P1=High[i1]; P2=Low[i2];  } 
 
  ObjectCreate(MarkName,OBJ_TREND,0,Time[i1],P1,Time[i2],P2);
  
  ObjectSet(MarkName,OBJPROP_RAY,False); // ラインではなく一部を描画します
  ObjectSet(MarkName,OBJPROP_BACK,False);
  ObjectSet(MarkName,OBJPROP_STYLE,STYLE_SOLID);
  ObjectSet(MarkName,OBJPROP_WIDTH,2);
 
  // 操作の利益性によってラインの色を指定します
  if(op_type==OP_BUY) 
  { 
    if(P1 <P2) СurColor = ColorProfitBuy;
    if(P1==P2) СurColor = ColorZeroBuy;
    if(P1 >P2) СurColor = ColorLossBuy;
  }
  if(op_type==OP_SELL) 
  { 
    if(P1 >P2) СurColor = ColorProfitSell;
    if(P1==P2) СurColor = ColorZeroSell;
    if(P1 <P2) СurColor = ColorLossSell;
  }
  ObjectSet(MarkName,OBJPROP_COLOR,СurColor);
}
//——————————————————————————————————————————————————————————————————————————————————————————————————————————

インディケータのパラメータには、特殊なパラメータOptimizmがあります。これは計算の楽観性の望む程度を指定します。もしそれがゼロより少ない場合、これは悲観的計算が実行されるということです。買い価格の為にシグナルバーのHighが選択され、売り価格の為にはLowが選択されます。このようにして、私達がこのシグナルに基づいて得ることができる最も悪い結果をモデル化します。もしその値がゼロより大きい場合、最も楽観的な計算がモデル化されます。最も低い価格で買い、最も高い価格で売ります。パラメータの値がゼロと等しい時、バーの始値に基づいて開いたり閉じたりする中立的行動がモデル化されます。まさにこのような状況が、多くの場合においてエキスパートアドバイザの取引時に実行されています。

結果の分析

それでは、ここでどのような結果が出たかを見てみましょう。これがジグザグの客観的な分析結果です。

ご覧のように、チャートは8つの損失の区間があることを示しています。ジ グザグは価格の最高値を使うので、これを完全に再構成する為にOptimizmパラメータに「1」を指定する必要があります。

もし私達がひどい取引をした場合、何が私達を待っているかは、Optimizmパラメータに「-1」を指定することで見ることができます。


余談

親愛なるトレーダーの皆さん、どうか私を酷く責めないでください。もし取引戦術の微細な点には興味がなく、結果だけに興味がある熟練したあなたの上司の元にいった場合、このインディケータは貴方にとって良い鞭になるかもしれません。テスターにZigZagのシグナルのアルゴリズムをアップロードし、Optimizm = 1とすると、チャートのこの部分から得られる最大利益の値を取得します。そして、もし貴方がいつもこの半分未満しか稼いでいなかったら、自分の職務に対して冷たく接しすぎていないかということを考えるきっかけになります。

一方で、このツールは根も葉もない過大な要求から守るあなたの武器となりえます。貴方のために立てた計画が意味のないことを客観的に証明できます。

ご覧のように、一つのOptimizmパラメータのみの使用は、テストするものの潜在能力の評価をするインディケータの使用を可能にします。そして、楽観的計算が利益を出さない場合、つまりシグナルのインディケータを更に綿密に修正しなければならない場合、他のパラメータを選出するか、最も最悪な場合、エキスパートアドバイザの開発にかかる時間と、シグナルのインディケータが役に立たないことを確認する為になくなってしまったであろうデポジットを節約して、これを見込みのないものとして破棄します。このようにして、私達がテストするインディケータは、時間だけでなくお金も節約できるのです。

取引システムのシグナルの分析

他のインディケータのバッファは、私達がテストするインディケータのシグナル配列を埋める唯一のソースではありません。本のどこかで、または広大無辺なインターネットの中で、それの為のインディケータもエキスパートアドバイザもない取引システムを見つけることができます。これはただのMQL4言語で簡単に実装できるルールの集成です。もし貴方がこのようなシステムのシグナルの計算をし、それらでシグナルバッファを埋める準備ができているのなら、テストするインディケータは貴方がシステムを使用して取得することができる結果を表示します。

もし取引システムの為にすでにコードが書かれているなら、貴方はその中にエキスパートアドバイザが動作するシグナルの計算を割り当てて、チャート上で直接『その動作結果』を作成することができます。勿論、同様のものをMetaTrader 4ストラテジーテスターで取得することができますが、インディケータは遥かに速く再構築を行い、テスターよりもより分かりやすくこれを表示します。

この場合、大事な事は、得られた結果のチャートを他のインディケータと一緒にすることができる点です。マークの垂直線は、追加のインディケータを通過し、これらを主要なシグナルの正確さの為にどのように使うことができるか、または不適切に動作している場所を知らせてくれます。最後に、試行錯誤する方法で選択されたこのようなパラメータの数値の方が、最適化の結果よりも、より貴方に合ったものになる場合があります。

例として、MACDの標準エキスパートアドバイザの既製コードを見てみましょう。以下のようになります。シグナル配列の記入ブロックは指標のテキストからコピー&ペーストされました。

  // シグナル配列に値を入れて配列の数を数える。
  for(i=DisplayBars;i>=0;i--) 
  {
    double MacdCurrent, MacdPrevious, SignalCurrent;
    double SignalPrevious, MaCurrent, MaPrevious;
  
    // to simplify the coding and speed up access
    // data are put into internal variables
    MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,i+0);
    MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,i+1);
    SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,i+0);
    SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,i+1);
    MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,i+0);
    MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,i+1);
    
    // check for long position (BUY) possibility
    if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious &&
       MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious) sBuy[i]=1;
       
    // check for short position (SELL) possibility
    if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && 
       MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent<MaPrevious) sSell[i]=1;
       
    if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious &&
       MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) sCloseBuy[i]=1;
 
    if(MacdCurrent<0 && MacdCurrent>SignalCurrent &&  MacdPrevious<SignalPrevious && 
       MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) sCloseSell[i]=1;
  }

そして、結果は以下のようになります。

シグナルのマークラインは、はっきりとMACDのチャートの交差点と一致することに注意してください。これらのチャートを見ながら、シグナルの中で何を変更すべきか決定してください。例えば、MaCurrentやMaPreviousのチェックを拒否するなどです。コードの微修正

  // シグナル配列に値を入れて配列の数を数える。
  for(i=DisplayBars;i>=0;i--) 
  {
    double MacdCurrent, MacdPrevious, SignalCurrent;
    double SignalPrevious, MaCurrent, MaPrevious;
  
    // to simplify the coding and speed up access
    // data are put into internal variables
    MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,i+0);
    MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,i+1);
    SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,i+0);
    SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,i+1);
    MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,i+0);
    MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,i+1);
    
    // check for long position (BUY) possibility
    if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious &&
       MathAbs(MacdCurrent)>(MACDOpenLevel*Point)) sBuy[i]=1;
       
    // check for short position (SELL) possibility
    if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && 
       MathAbs(MacdCurrent)>(MACDOpenLevel*Point)) sSell[i]=1;
       
    if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious &&
       MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) sCloseBuy[i]=1;
 
    if(MacdCurrent<0 && MacdCurrent>SignalCurrent &&  MacdPrevious<SignalPrevious && 
       MathAbs(MacdCurrent)>(MACDCloseLevel*Point)) sCloseSell[i]=1;
  }

これで貴方はどのような結果がもたらされるか見ることができます。操作数は19から51までに増えましたが、総利益は損失になったことから、シグナルの質を改善するというアイディアは最も良いものではなかったと言えます。

ファンタジーテスト

開発者やトレーダーの頭には、恐らくまだ実行していないアイディアがあるはずです。インディケータのテストは、これらを素早く視覚化し評価してくれます。もしアイディアが正しく、得られた結果が肯定的であると思われる場合、実際のインディケータやエキスパートアドバイザの開発について考えることができます。この場合、インディケータのテスト結果は、同時に開発に対する技術課題の例であり、既製製品の受け渡しを実行することができる検査例となります。

例として、最も簡単な『システム』、普通の移動平均線インディケータを使用して買います。МАが上昇したら買い、МАが下降したら売ります。このアイディアの利益性をどれほど簡単にテストすることができるか見てください。シグナルの記入ブロックは次のようになります。

  // シグナル配列に値を入れて配列の数を数える。
  for(i=DisplayBars;i>=0;i--) 
  {
    double m1=iMA(NULL,0,MAPeriod,0,MAMode,MAPrice,i+1);
    double m2=iMA(NULL,0,MAPeriod,0,MAMode,MAPrice,i+2);
    
    // オープンの条件は同時、反対の注文のクローズの条件
    if(m2<=m1 && MathAbs(m1-m2)>0.2*Point) { sBuy[i]=1; sCloseSell[i]=1; sBuyCnt++; sSellCloseCnt++; }
    if(m2>=m1 && MathAbs(m1-m2)>0.2*Point) { sSell[i]=1; sCloseBuy[i]=1; sSellCnt++; sBuyCloseCnt++; }
  }

結果は以下のようになります。

悪くはありませんが、最も良い結果ではありません。私たちは信じられない程の利益を夢見ていますので。利益のある取引での稼ぎを多くする為に、МАの期間を減らしてみましょう。期間を15から7に減らし、私達は日平均利益を2倍ほどに増やしました。

残るは利益と損失の取引の相関を8:2にします。この為には少し頑張らなければなりませんが、ここからは私抜きでお願いします。

まとめ

貴方の手の中には、インディケータと取引シグナルの高速分析の為のもう一つのツールがあります。勿論、これはテスターにとって代わることはできませんし、実際の取引なら尚更です。これを使って得た全てのデータは、質の良い評価的性質を持っています。しかしながら、動作の利便性、分かりやすさ、そして取得結果の速度は、全ての開発者にとって有用であると私に思わせてくれます。

これを使うことで、そのプロセスに多くのエネルギーと時間を費やすことなく、取引アイディアを効率的に検証することができます。これは、取引シグナルやインディケータでの特定の動作の将来性や非将来性の独特な証拠となりえ、思慮深い研究者や実験者の手の中で、インディケータのパラメータの微細な最適化のツールとなりえると思います。


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

添付されたファイル |
IndicatorTester.mq4 (15.96 KB)
テクニカル指標や取引シグナルの利益表のビジュアル最適化 テクニカル指標や取引シグナルの利益表のビジュアル最適化
この記事は、前の記事「テクニカル指標とアラートの利益のビジュアルテスト」の関連記事です。パラメータ変更プロセスに双方向性を加え、検査の目的を変えることにより、シグナルを用いて取引結果予想を表示するだけでなく、メインチャートのシグナルパラメータ値を制御する役割として仮想スライドを動かすことで、取引レイアウトやバランスチャート、取引結果を即座に取得できるツールを作成します。
チャネルを利用したトレードのためのエキスパートアドバイザー チャネルを利用したトレードのためのエキスパートアドバイザー
このエキスパートアドバイザーはチャネルラインをプロットします。上と下のチャネルラインがサポート・レジスタンスレベルとして振る舞います。エキスパートアドバイザーは基準点を設け、値が届くかチャネルラインを越えるかする度にサウンド通知をおこない、関連する印を描きます。フラクタルなフォーメーションにおいて、対応する矢印が最後のバーに現れます。ラインブレイクアウトは大きくなっていくトレンドの可能性を示唆します。このエキスパートアドバイザーは幅広い範囲で批評されます。
ローソク足の動きを予測するための簡単な方法 ローソク足の動きを予測するための簡単な方法
価格変動の傾向を知ることは、取引操作から良い結果を得るためには大切なことです。ローソク足が与えうる傾向についての、いくつかの情報があります。この記事では、ローソク足の動きを予測する、いくつかの簡単なアプローチを検証していきます。</div>
Lite_EXPERT2.mqhファイル - EAの最適化の実践例 Lite_EXPERT2.mqhファイル - EAの最適化の実践例
この記事では、筆者はEA構築の具体例にて、Lite_EXPERT2.mqhファイルの関数の紹介を続けます。Average True Range (ATR)の指標値に基づいて明確にされる取引から取引へと変動する指値注文の使用案を検証します。