English Русский 中文 Español Deutsch Português
テクニカル指標や取引シグナルの利益表のビジュアル最適化

テクニカル指標や取引シグナルの利益表のビジュアル最適化

MetaTrader 4 | 5 11月 2015, 10:03
800 0
Sergey Kravchuk
Sergey Kravchuk

この記事は、前の記事「テクニカル指標とアラートの利益のビジュアルテスト」の関連記事です。パラメータ変更プロセスに双方向性を加え、検査の目的を変えることにより、シグナルを用いて取引結果予想を表示するだけでなく、メインチャートのシグナルパラメータ値を制御する役割として仮想スライドを動かすことで、取引レイアウトやバランスチャート、取引結果を即座に取得できるツールを作成します。

 

はじめに

まず皆さんにご注意いただきたいのは、今回紹介するツールも前の記事で説明した物同様、魔法のツールではないということです。単に計算を早くしたり結果を分かりやすく表示したりするだけで、損失を完全回避し利益のみを得ることができるものではありません。テクニカル指標の図はトレーダーにとってシグナルを用いた取引をする際の栄養サプリメント的なものであると考えたほうがいいでしょう。しかしながら、短期取引(特に日計り取引)の際には役立つツールであるといえます。

EAの詳細とともにフォーラムのスレッドに書かれたコメントを見て、指標に改良を加えようと思い立ちました。 コメントには「2009年は順調で、今のところ満足しています。シグナル監視の簡易化に関しては…(以下略)」とありました。ここで話題に上がっていたEAはシグナル、時間軸面では実によく機能していました。しかしながら、パラメータを変更しようとした場合、この優秀なEAが豹変し、証拠金の大半を瞬時に失う大惨事につながりかねませんでした。EAの作成者は、作成したEAを実際の取引に使用することは勧めていませんでしたが、「どうしたら取引結果のチェックだけでなく、取引方法の予想もできるのだろうか」という問題が心に引っかかりました。どうにかして、いくつかのシグナルや戦略の無効性を視覚的わかりやすくしたかったのです。そしてもう一つ引っかかったのは、既存のパラメータで取引してもEAは十分な利益をもたらすという点です。もし手動取引で同じような取引ができた場合、私はその結果に大変満足することでしょう。ですが、もしまださらに改善の余地があるとしたら…?今回はこの問題の解決策を探っていきましょう。


問題定義

以前の記事、「テクニカル指標とアラートの利益のビジュアルテスト」で使用した指標に基づいてこの研究を行います。言い換えれば、必要な作業の大部分はすでに前回終えてしまったので、今回はそれに改良加えることになります。以前の指標には何が足りなかったのは、簡単なパラメータの選択方法です。毎回テクニカル指標の「パラメータ」でパラメータの設定をして、表示された結果を分析するのは、面倒です。そもそも指標は既存のシグナルを確認するために作られていて、今回はそれとは別のことをしようとしているので、仕方がないでしょう。では何が必要なのでしょうか?MTストラテジーテスターを頻繁に使う人は良くわかるでしょう。取引結果の分析すに、バランスチャートやシグナル値計算パラメータの変更の可能性です。


バランスチャート

一番簡単なのはバランスチャートです。全ての取引動作がチャートに表示されるので、必要なのは予想される取引結果の値を合計を出すことだけです。上昇・下落チャートを別ウィンドウで開けるようになります。結果を貨幣価値として示したい方には以下のパラメータをお勧めします。


エミュレーションスライダ

自動取引用プラットフォームをトレーダーとの相互性を要するタスク用に調整するのは難しかったです。スタンダードリソースでは、テクニカル指標の選択、プロパティの呼び出しと編集を1度に1種類しかできませんでした。このように、いくつもの選択肢を一つ一つ試すには時間と手間を要します。何度もテストを行っているうちに訳が分からなくなってしまうこともあるでしょう。

始業やEAでは、ボタン、チェックボックス、コンボボックス、スライダなどのGUIの通常設定が(他のプログラミング言語で書かれたDLLライブラリを使用しない限り)使用できません。そこで、何らかの代替法を探す必要があります。今回は度のチャートにも簡単に追加できる三角記号を通常のスライダに使って、指定の最小値から最大値まで値を変更できるようにしましょう。2つの上下(または左右)スライダを作成し、双方の間にもう1つスライダを作成した場合、適切なスライダーの線形モデルを得られます。スライダーは縦方向に設置するとよりスムーズに値を変更できます。複数のパラメータを同時に変更するには、複数の三角形を同時に使用できるようにする必要があります。

三角スライダの機能は以下のようになります。

double ParamValue(int ParamNo, string ParamName, double ParamValue, double vMin, double vMax, color clr)
{
  double Triangle[3],vCur, WMax, WMin; datetime tt1, tt2;

  // 三角が無い場合、新しく三角を作る
  if(ObjectFind(ParamName) < 0)
  {
    // 現在のスケールに基づいてチャートの境界線を決定する
    WMax = WindowPriceMax();  WMin = WindowPriceMin();

    // 点の座標を時間によって決定する
    tt1 = Time[0] + Period()*60*ParamNo*20; tt2 = tt1 + Period()*60*20;

    // 点の座標を価格によって決定する
    vCur = WMin + (ParamValue - vMin) * (WMax - WMin) / (vMax - vMin);

    // オブジェクトを作成し、指定の色で塗りつぶす。
    ObjectCreate(ParamName,OBJ_TRIANGLE, 0, tt1,WMax, tt2,vCur, tt1,WMin);
    ObjectSet(ParamName,OBJPROP_COLOR,clr);
  }

  // 三角が存在する場合、座標を取得する
  Triangle[0] = ObjectGet(ParamName,OBJPROP_PRICE1);
  Triangle[1] = ObjectGet(ParamName,OBJPROP_PRICE2);
  Triangle[2] = ObjectGet(ParamName,OBJPROP_PRICE3);

  // 昇順で頂点を加える
  ArraySort(Triangle);

  // 中心点座標をvMinとvMaxの間にある真値に変える
  vCur = vMin + (Triangle[1] - Triangle[0]) / (Triangle[2] - Triangle[0]) * (vMax - vMin);

  // オブジェクトのコメントに値を書く
  ObjectSetText(ParamName,DoubleToStr(vCur,2));

  // main関数の値に戻る
  return(vCur);

}

コメントには関数計算アルゴリズムが詳細に説明されていますから、ここでは必要最低限の関数のパラメータのみ見ていきましょう。

ParamNo – 使用するパラメータの番号(三角の記号が互いにどう時間軸上を動くか決定します。)必要に応じであとからサイズや位置を変更できます。

ParamName – ツールトップに表示するそれぞれの三角マークを特定するためのパラメータ名

ParamValue – パラメータ名に対するパラメータ値(最適化のために前記検出下限値vMin と出力上限値 vMaxとの差から求めます)

сlr – 三角記号の色

コードは以下のようになります。

MAPeriod  = ParamValue(0, SliderPrefix+"MA Period", MAPeriod, 5, 35, Blue);

RSIPeriod = ParamValue(1, SliderPrefix+"RSI Period", RSIPeriod, 2, 25, Red);

RSILevel  = ParamValue(2, SliderPrefix+"RSI Level", RSILevel, 5, 95, Orange);

計算された値が対応するシグナル計算に使用されます。

計算コード開発とデバッグの例として、ユーザー Helen (HI_Line_E_RSI_MA.mq4)作成の指標を選びました。今回の指標で動作するようシグナル計算コードを少々書き換えましたが、主たる部分はほぼ同じです。

// シグナル配列に値を入れて配列の数を数える
  for(i=DisplayBars;i>=0;i--)
  {

    double t1=iRSI(NULL,0,RSIPeriod,MAPrice,i+1);
    double t11=iRSI(NULL,0,RSIPeriod,MAPrice,i+2);

    double t2=iMA(NULL,0,MAPeriod,0,MAMode,MAPrice,i+1);
    double t3=iMA(NULL,0,MAPeriod*3,0,MAMode,MAPrice,i+1);

    if (t1>RSILevel&&t11<RSILevel&&t1>t11&&t1>RSILevel&&t2>t3) {sBuy[i]=1; sBuyCnt++;}
    if (t1<(100-RSILevel)&&t11>(100-RSILevel)&&t1<t11&&t1<(100-RSILevel)) {sCloseBuy[i]=1; sBuyCloseCnt++;}

    if (t1<(100-RSILevel)&&t11>(100-RSILevel)&&t1<t11&&t1<(100-RSILevel)&&t2<t3) {sSell[i]=1; sSellCnt++; }
    if (t1>RSILevel&&t11<RSILevel&&t1>t11&&t1>RSILevel) {sCloseSell[i]=1; sSellCloseCnt++;}
  }

長期移動平均線を作成するための4つ目のパラメータは作成しないことにしました。今回は主要MAの3倍の長さを使いますが、この設定は必要に応じて変更可能です。

もう一つベースの指標に追加したのはバランス曲線の計算コードです。

// バランスチャートを作成
// 利益の値を集計 
i2 = DisplayBars; bBallance[i2] = 0; 
for(i=DisplayBars-1;i>=0;i--) { if(bBallance[i] != 0) { bBallance[i2] = bBallance[i2+1] + bBallance[i]; i2--;  } }
double multiplier; if(ProfitInPoints) multiplier = 1; else multiplier = ToCurrency;
for(i=0;i<DisplayBars-2;i++) bBallance[i] = bBallance[i+i2+1] * multiplier;
SetIndexStyle(0,DRAW_HISTOGRAM,STYLE_SOLID,ProfitWidth,Blue);

1つ目のループは利益値の累積合計を計算し、2つ目のループは値の一覧を作成します。因みに、オーダー開始・終了の縦線は下のチャートとは対応していない(そのためデフォルトでは無効になっています)ので、チャート同士を見比べる必要はありません。

結果として、指標コードは以下のようになります。

/*///——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

    IndicatorOptimizer.mq4 
  
    テクニカル指標とアラートの利益性ビジュアルテスト
    
    Copyright © 2009、セルゲイ・クラフチュク、  http://forextools.com.ua

/*///——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
#property copyright "Copyright © 2006-2009, Sergey Kravchuk. http://forextools.com.ua"
#property link      "http://forextools.com.ua"

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_level1 0

// チャート部分表示のパラメータ
extern bool   ShowZZ          = true;           // 33を描くか
extern bool   ShowMARKERS     = false;           // 縦のマーカーラインを描くか
extern int    ProfitWidth     = 1;
extern bool   ProfitInPoints  = true;

//チャートの作成日付
extern datetime DateStart     = D'1.01.1970';
extern datetime DateEnd       = D'31.12.2037';

//利益計算の設定
extern double LotForCalc      = 0.05;           // ロットサイズ

// RSIのパラメータ
extern int    RSIPeriod       = 8;              // RSIの期間
extern int    RSILevel        = 73;             // RSIレベル

// MAのパラメータ
extern int    MAPeriod        = 20;             // 移動平均線の期間設定
extern int    MAMode          = 3;              // 0-MODE_SMA 1-MODE_EMA 2-MODE_SMMA 3-MODE_LWMA
extern int    MAPrice         = 6;              // 0-Close 1-Open 2-High 3-Low 4-(H+L)/2 5-(H+L+C)/3 6-(H+L+2*C)/4


// MACDのパラメータ
extern double MACDOpenLevel   = 3;              
extern double MACDCloseLevel  = 2;
extern double MATrendPeriod   = 26;

// 買い線の色
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;
double bBallance[]; // 動作バランスを整える
int IndicatorWindowNo;  // 指標のウィンドウ番号
//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
// サービスコード
#define MrakerPrefix "IO_"
#define SliderPrefix "SL_"
#define OP_CLOSE_BUY  678
#define OP_CLOSE_SELL 876
//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
int init()   
{ 
  SetIndexBuffer(0,bBallance);
  IndicatorShortName("IndicatorOptimizer");
  
  return(0); 
}
int deinit() 
{ 
  ClearMarkers(); 
  ClearSliders();
  return(0); 
}

double ParamValue(int ParamNo, string ParamName, double ParamValue, double vMin, double vMax, color clr)
{
  double Triangle[3],vCur, WMax, WMin; datetime tt1, tt2; 

  // 三角がない場合、新しく三角を作成する
  if(ObjectFind(ParamName) < 0)
  {
    // 現在のスケールに基づいてチャートの境界線を決定する
    WMax = WindowPriceMax();  WMin = WindowPriceMin();

    // 点の座標を時間によって決定する
    tt1 = Time[0] + Period()*60*ParamNo*20; tt2 = tt1 + Period()*60*20;
    // 点の座標を価格によって決定する
    vCur = WMin + (ParamValue - vMin) * (WMax - WMin) / (vMax - vMin);
    // オブジェクトを作成し、指定の色で塗りつぶす
    ObjectCreate(ParamName,OBJ_TRIANGLE, 0, tt1,WMax, tt2,vCur, tt1,WMin);
    ObjectSet(ParamName,OBJPROP_COLOR,clr);
  }
  // 三角が存在する場合、三角点の座標を取得する
  Triangle[0] = ObjectGet(ParamName,OBJPROP_PRICE1);
  Triangle[1] = ObjectGet(ParamName,OBJPROP_PRICE2);
  Triangle[2] = ObjectGet(ParamName,OBJPROP_PRICE3);
  // 昇順で頂点を追加する
  ArraySort(Triangle);
  // 中心点座標をvMinとvMaxの間にある真値に変更する
  vCur = vMin + (Triangle[1] - Triangle[0]) / (Triangle[2] - Triangle[0]) * (vMax - vMin);
  // オブジェクトの説明を設定する
  ObjectSetText(ParamName,DoubleToStr(vCur,2)); 
  // main関数の値に戻る
  return(vCur); 
}


//—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
int start() 
{ 
  double Profit=0,P1,P2; int CntProfit=0,CntLoose=0,i1,i2;
  // ポイントから指定されている通貨ペアへの交換係数
  double ToCurrency = MarketInfo(Symbol(),MODE_TICKVALUE)*LotForCalc;    
  
  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // テクニカル分析の数値を再表示する場合、マークがついたものを全て削除する
  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);

  // バランスの計算の準備
  ArrayInitialize(bBallance,0); 
  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————


  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // 三角スライダのパラメータを取得または必要に応じ作成する
  MAPeriod  = ParamValue(0, SliderPrefix+"MA Period", MAPeriod, 5, 35, Blue);
  RSIPeriod = ParamValue(1, SliderPrefix+"RSI Period", RSIPeriod, 2, 25, Red);
  RSILevel  = ParamValue(2, SliderPrefix+"RSI Level", RSILevel, 5, 95, Orange);
  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————


  // シグナル配列に値を入れて配列の数を数える。
  for(i=DisplayBars;i>=0;i--) 
  {
    double t1=iRSI(NULL,0,RSIPeriod,MAPrice,i+1);
    double t11=iRSI(NULL,0,RSIPeriod,MAPrice,i+2);

    double t2=iMA(NULL,0,MAPeriod,0,MAMode,MAPrice,i+1);

    double t3=iMA(NULL,0,MAPeriod*3,0,MAMode,MAPrice,i+1);

    if (t1>RSILevel&&t11<RSILevel&&t1>t11&&t1>RSILevel&&t2>t3) {sBuy[i]=1; sBuyCnt++;}
    if (t1<(100-RSILevel)&&t11>(100-RSILevel)&&t1<t11&&t1<(100-RSILevel)) {sCloseBuy[i]=1; sBuyCloseCnt++;}

    if (t1<(100-RSILevel)&&t11>(100-RSILevel)&&t1<t11&&t1<(100-RSILevel)&&t2<t3) {sSell[i]=1; sSellCnt++; } 
    if (t1>RSILevel&&t11<RSILevel&&t1>t11&&t1>RSILevel) {sCloseSell[i]=1; sSellCloseCnt++;}
  }

 
        //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // シグナルの繰り返し削除し、最初のものをチャートの左側に表示する
  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++;
  }
  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // マークを付けてZZを描くことで、利益を計算する
  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // 買い取引の実行中
  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; // 点を取得するのための新しいバー

    // 表示される価格を決定する 
    P1=Open[i1]; P2=Open[i2];  
    
    P1/=Point; P2/=Point; // ポイントへの交換
    
    // 利益を決め、対応するバッファに格納する
    if(i1>=0) 
    { 
      Profit=Profit+P2-P1; // 累積利益を計算する
      if(P2-P1>=0) CntProfit++; else CntLoose++; // 注文数を数える
      DrawLine(i1,i2,OP_BUY); // 買い注文を表す
      PlaceMarker(i1,OP_BUY); 
      PlaceMarker(i2,OP_CLOSE_BUY); 
      
      bBallance[i2] += P2-P1;
    }
  }
  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // 売り取引の実行中
  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; // 点を取得するのための新しいバー

    // 最適化パラメータにより表示する価格を決定する
    P1=Open[i1]; P2=Open[i2]; 
    
    P1/=Point; P2/=Point; // ポイントへの交換
    
    // 点が2つある場合、利益を決めてバッファに格納する
    if(i1>=0) 
    { 
      Profit=Profit+P2-P1; // 累積利益を計算する
      if(P1-P2>=0) CntProfit++; else CntLoose++; // 注文数を数える
      DrawLine(i1,i2,OP_SELL); // 売り注文を表す
      PlaceMarker(i1,OP_SELL); 
      PlaceMarker(i2,OP_CLOSE_SELL);
      
      bBallance[i2] += P1-P2;
    }
  }

  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // バランスチャートを作成する
  // 利益の値を集計する 
  i2 = DisplayBars; bBallance[i2] = 0; 
  for(i=DisplayBars-1;i>=0;i--) { if(bBallance[i] != 0) { bBallance[i2] = bBallance[i2+1] + bBallance[i]; i2--;  } }
  double multiplier; if(ProfitInPoints) multiplier = 1; else multiplier = ToCurrency;
  for(i=0;i<DisplayBars-2;i++) bBallance[i] = bBallance[i+i2+1] * multiplier;
  SetIndexStyle(0,DRAW_HISTOGRAM,STYLE_SOLID,ProfitWidth,Blue);

  //———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
  // コメントのために最終値を決める  
  int Cnt=CntProfit+CntLoose; // 操作数
  string msg="+TimeToStr(MathMax(DateStart,Time[Bars-1]))+" - "+TimeToStr(MathMin(DateEnd,Time[0]))+"\n\n";
  
  msg=msg + 
  "RSIの期間: " + RSIPeriod + "\n" +
  "RSIレベル:" + RSILevel + "\n" +
  "移動平均線の期間:" + MAPeriod + "\n\n" +
  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=ObjectsTotal()-1;i>=0;i--) if(StringFind(ObjectName(i),MrakerPrefix)==0) ObjectDelete(ObjectName(i)); 
}
void ClearSliders() 
{ 
  for(int i=ObjectsTotal()-1;i>=0;i--) if(StringFind(ObjectName(i),SliderPrefix)==0) ObjectDelete(ObjectName(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)
{
  if(!ShowZZ) return; // ZZが無効であると表示する
  
  color СurColor;
  string MarkName=MrakerPrefix+"_"+i1+"_"+i2;
  double P1,P2;
  
  // Optimizmパラメータによって表示される価格を決定する
  P1=Open[i1]; P2=Open[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パラメータに対する回避策を実施しませんが、ご了承ください。この指標のアップデートでは、現在バーのシグナルが前のバーの値から計算されます。それは取引を改善する古典的なアプローチです。完了したばかりのバーの値を分析し、現在のバーのポジションを開きます。そのため、分析結果が信頼できるものだと言えるでしょう。


最適化処理の実行中

テクニカル指標をコンパイルしてチャートに挿入すると、分析を行うことができます。それについての説明はここでは割愛します。指標の実際の動作については添付の動画をご覧ください。

注意:チックの際に毎回、指標の値が再計算されます。そのため、三角スライダを動かした場合、新価格更新を待つか、チャートの内容を手動で更新する、または、チックエミュレーターを使用する必要があります。

最適化処理は「もしこうなら…?」という面白いゲームになるでしょう。三角スライダを選択し動かすだけでいいのですから。水平線上にある頂点の座標について考える必要がなくなります。重要なのは縦線上にある頂点の座標のみです。このように、直感や実戦経験をもとに三角刃スライダを動かし、結果を見ていきます。経験が少なくても試行錯誤を繰り返すことでふさわしいパラメータを設定できるようになるでしょう。


指標の使用方法

1、すべきではないこと

以前のもの同様、このテクニカル指標も、動作をよく理解して使わなければなりません。シグナル計算コードの取り替えや使用するシグナル数の変更ができます。ですが、ユーロドルの30分足チャートで指標のパラメータの最適化を行って取引に成功たとしても、他の通貨ペアや時間枠で同じように上手くいくとは限らないということを気に留めておいてください。なぜかというと、1分足と日足を見てみるとわかるでしょう。バーの性質やサイズの違いは一目瞭然です。

通貨ペアによる違い少々わかりにくいと思いますが、これについては「Market Diagnostics by Pulse」で詳しく取り上げました。上述の記事ではスクリーンショットを用い、シグナル計算ブロックの設定が同じでも通貨ペアにより取引結果に違いが生じる理由を説明しています。


2、すべきこと

しかしながら、「強みは弱さの中にある」と言われるように、思ったほど悪くないかもしれません。不利にしか見えなくても、有利な点が無いというわけではありません。上昇トレンドが続いてる日足チャートを見てみましょう。期間最初に最適化された指標は、期間中に、利益をもたらさないと言えるでしょうか?

私と同じようにこのテクニカル指標を取引で使う予定なら、その時々で通貨ペアや時間軸を再設定しなければなりません。例えば、HelenのEAなどを使って、ときどきこの指標を再設定しながら、自動売買を行うことができます。今回の指標はその再設定の作業が好きな時に簡単に行えるので、さまざまなチャートに基づいて FX 取引できます。


まとめ

相場というのはまったく予想できないものです。100%確かなシグナルでも相場が一瞬で反転する可能性があります。プロトレーダーがこの記事について話し合ったら、Oandaなど基本的なシグナルを使わなければ、価格がどうなるのか分からず、安定した利益は得られないという意見が出るでしょう。それにも一理あるのですが、それは何千ドルも使って取引する場合のみ使えるアプローチであると言えます。

少額取引なら、私が作成したテクニカル指標はおすすめのツールです。価格変動の全貌を知ることはできないのですから、反転点を一生懸命探してそこから1セントでも利益を出そうとすることは無意味なのです。それと比べれば、数日、数週間などの長期トレンドには何らかの特徴あるはずなので、トレンドの開始点を見つけ、それに合わせて指標のパラメータを最適化することができれば、ある程度の期間、利益を得ることができるでしょう。「風向」が変わったとしても、そんなに大きい問題ではないと感じるようになるでしょう。このテクニカル指標なら、以前より速くシグナルを、再最適化できるのですから。

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

添付されたファイル |
IndicatorOptimizer.zip (1820.28 KB)
ローソク足の動きを予測するための簡単な方法 ローソク足の動きを予測するための簡単な方法
価格変動の傾向を知ることは、取引操作から良い結果を得るためには大切なことです。ローソク足が与えうる傾向についての、いくつかの情報があります。この記事では、ローソク足の動きを予測する、いくつかの簡単なアプローチを検証していきます。</div>
インディケータとシグナルの利益性のビジュアルテスト インディケータとシグナルの利益性のビジュアルテスト
取引シグナルのインディケータの選択や、それらの計算方法は、通常、これらのシグナルを使用するエキスパートアドバイザのバックテストを行い分析します。しかし、各インディケータに基づいてエキスパートアドバイザを作成するのは、常に可能で必要で妥当であるわけではありません。他のインディケータのシグナルでの、取引の利益性の能率的な計算は、自分でそれらのシグナルを集め、それに基づく理想的な取引の図を描く、特別なインディケータを使う事で行う事ができます。これを使う事で、視覚的に結果を評価するだけでなく、素早く最適なパラメータを選出することができます。
取引口座の分析 取引口座の分析
この記事は、MT4での取引履歴を元に取引の分析を行うためのツールについて説明しています。特に、その技術面を分析します。分析後に、取引要因の改善方法をまとめます。分析には、MQLab™ Graphic Reportスクリプトを使用します。
チャネルを利用したトレードのためのエキスパートアドバイザー チャネルを利用したトレードのためのエキスパートアドバイザー
このエキスパートアドバイザーはチャネルラインをプロットします。上と下のチャネルラインがサポート・レジスタンスレベルとして振る舞います。エキスパートアドバイザーは基準点を設け、値が届くかチャネルラインを越えるかする度にサウンド通知をおこない、関連する印を描きます。フラクタルなフォーメーションにおいて、対応する矢印が最後のバーに現れます。ラインブレイクアウトは大きくなっていくトレンドの可能性を示唆します。このエキスパートアドバイザーは幅広い範囲で批評されます。