リキッドチャート

Serhii Shevchuk | 24 12月, 2015


はじめに

あるとき私はタイムフレーム H4 以上のチャートはブローカーごとに違って見えることに気づきました。その理由はブローカーが異なるタイムゾーンに存在することでした。タイムゾーンにそれほど差はないのに同じチャートの特定箇所が著しく違うことがあります。あるチャートでは明確な反転パターンがあり、別のチャートの同じ箇所には明確なパターンがなかったのです。

それでつねに右側に完全なクローズしているバーがくるような H1 のチャート再作成をするインディケータを書こうという思いがよぎりました。価格源としてM1 期間が選択されました。結果、時間ごとのチャートは毎分再作成され、1時間後には同じ時間毎のチャートが 60 通りもありました。その形式はなめらかに流れるように変化し、最初のパターンではまったくなかった隠れたパターンを表現しました。

私はその特別な外観からこのインディケータを『リキッドチャート』と名づけました。基本期間の新規バーが出現するとかスタティックシフトの値が変化するときのどちらかにプロットモードによってこのチャートは『流れる』(再作成される)のです。本稿では『リキッドチャート』をプロットする原則を考察し、それからインディケータを書き、この技術をインディケータによるエキスパートトレードとパターンによるエキスパートトレードに使用する場合の効率を比較します。


1. プロット原則

始める前に用語の定義を行います。

シフト-結果として生じるチャートバーの始値とソースチャートバーの始値の差

現タイムフレーム-ソースチャートのタイムフレーム

基本タイムフレーム-結果チャートのバーを形成するために利用していく価格を持つタイムフレーム

基本期間は現行期間を越えません。現行期間は余りなしで基本期間で割ります。基本タイムフレームに対する現行タイムフレームの比率が高いほど、結果チャートのバリエーションは増えます。とはいうものの、比率が大きすぎると、基本タイムフレームの履歴データが必要な結果チャートバーを描くのに十分ではない可能性があります。

チャートをプロットする方法は3とおりあります。

静的シフトモードではバーの開始時刻は設定時刻に移動します。オープンモードの動的シフトはバーがオープンした直後のように、クローズモードではバーがすぐにクローズするように見えるのです。

詳しく見ていきます。


1.1. 静的シフトを伴うチャート

このモードでは各バーの開始時刻は基本タイムフレームの設定数に等しい分数だけ移動します。われわれはそれをシフトと呼びます。このように設定されたシフトが 0 であれば、チャートは正確にソースチャートと同じものです。基本タイムフレームが15分とすると、シフト 1 は 15 分です。シフト 2 は30分、などです。

シフトは (k-1)を超えることはできません。ここで k は基本タイムフレームに対する現タイムフレームの比率です。現タイムフレーム H1 と基本タイムフレーム M1 であれば許容できる最大シフトは基本タイムフレームの 60/1 - 1 = 59 で、これは59 分です。基本タイムフレームが M5 なら最大許容シフトは基本タイムフレームの 60/5 - 1 = 11 でそれは55分です。

現タイムフレーム H1 と15分のシフトでのバー開始時刻は 00:15、01:15、02:15 などです。現タイムフレーム M15 とシフト 1 分でのバー開始時刻は 00:16、00:31、00:46、01:01 などです。

シフトが限界値に近いときのようなチャートはソースチャートとほとんど変わりません。顕著な違いが出るのはシフト値が許容範囲の真ん中に近いときです。

静的シフトを伴うチャート

図1 基本タイムフレーム M15 でシフト値1 の時間ごとのバー形成例


1.2. オープンモードで動的シフトを伴うチャート

このモードでは、基本タイムフレームの新規バーが出現するたびにシフトが再計算されます。同時に、シフトはチャートの末尾にあるバー(直近価格)の時間が基本タイムフレーム値を越えないように計算されます。現タイムフレームが H1 で基本タイムフレームが M5 であれば、それは一番右のバーがオープンしたのは5分以前ではないように見えます。

動的シフトを伴うチャート、バーの開始

図2 基本タイムフレーム M15 でオープンモードの動的シフトを伴うバー形成例


1.3. クローズモードで動的シフトを伴うチャート

このモードでは、オープンモード同様、基本タイムフレームの新規バーが出現するたびにシフトが再計算されます。唯一異なる点は、シフトがチャート末尾のバー(直近価格)の存在する時刻が現タイムフレームと基本タイムフレームの差より大きいかまたは等しくなるように計算されていることです。現タイムフレーム H1 と基本タイムフレーム M5において右端のバーは5分以内にクローズするように見えます。

動的シフトを伴うチャート、バーの完了

図3 基本タイムフレーム M15 でクローズモードの動的シフトにおけるバーの1時間ごとの形成例


2. データ変換

GetRatesLC()関数は設定されたシフトを考慮しつつ履歴データを変換するために書かれています。それは MqlRates タイプのストラクチャを持つ配列に変更された履歴データを書き込みます。CopyRates() 関数に類似しています。

int GetRatesLC(
   int             start_pos    // source for copying
   int             len,         // amount to copy
   MqlRates&       rates[],     // target array
   ENUM_TIMEFRAMES base_period, // basic timeframe
   int&            shift        // shift
   );

パラメータ

start_pos

現タイムフレームにおける第一エレメント[in] インデックスそれはデータ変換とバッファにコピーするスタート地点です。

len

[in] コピーされたエレメント数

rates[]

[out] MqlRates タイプの配列

base_period

[in] 基本タイムフレーム

shift

[in] [out] シフトそれは以下の値を受け付けます。

説明
-2 オープンモード(バー形成の初め)でシフトを計算します
-1 クローズモード(バー形成の終わり)でシフトを計算します
0 ... N 設定されたシフトを適用します。値 0~N を受け付けます。
N = Tcur/Tbase - 1. ここで Tcur は現タイムフレーム、Tbase は基本タイムフレームです。

表1 シフトパラメータの許容値

関数が正常に実装されると、計算された値が -2 ~-1 であればシフトが計算された値を受け取ります。

戻り値

コピーされたエレメント数またはエラーコード

コード 説明
-1 誤った指定をされた基本タイムフレーム
-2 誤った指定をされたシフト

表2 返されたエラーコード

以下は liquidchart.mqh ファイルからの GetRatesLC() 関数のコードです。

int GetRatesLC(int start_pos,int len,MqlRates &rates[],ENUM_TIMEFRAMES base_period,int& shift)
  {
   //--- number of basic timeframes contained in the current one  
   int k=PeriodSeconds()/PeriodSeconds(base_period);
   if(k==0)
      return(-1);//basic timeframe specified incorrectly
   //---
   MqlRates r0[];
   ArrayResize(rates,len);
   if(CopyRates(_Symbol,_Period,start_pos,1,r0)<1)
      return(0);// no data
   //---
   int sh;
   if(shift>=0)
     {
      //--- fixed shift
      if(shift<k)
         sh=shift;
      else
         return(-2);//--- shift specified incorrectly   
     }
   else if(shift==-1)
     {
      //--- shift to be calculated (dynamic, beginning of the bar formation)
      sh=int((TimeCurrent()-r0[0].time)/PeriodSeconds(base_period));
     }
   else if(shift==-2)
     {
      //--- shift to be calculated (dynamic, end of the bar formation)
      sh=1+int((TimeCurrent()-r0[0].time)/PeriodSeconds(base_period));
      if(sh>=k)
         sh = 0;
     }
   else
      return(-2);//shift specified incorrectly       
   //--- opening time of the basic period bar, which is the beginning of the current period bar formation
   //--- synchronization of the time of opening bars takes place relative to the tO time
   datetime tO;
   //--- closing time of the bar under formation, i.e. opening time of the last bar of basic timeframe in the series
   datetime tC;
   tO=r0[0].time+sh*PeriodSeconds(base_period);
   if(tO>TimeCurrent())
      tO-=PeriodSeconds();
   tC=tO+PeriodSeconds()-PeriodSeconds(base_period);
   if(tC>TimeCurrent())
      tC=TimeCurrent();
   int cnt=0;
   while(cnt<len)
     {
      ArrayFree(r0);
      int l=CopyRates(_Symbol,base_period,tC,k,r0);
      if(l<1)
         break;
      //--- time of the bar with the (l-1) index does not have to be equal to tC
      //--- if there is no bar with the tC time, it can be the nearest bar
      //--- in any case its time is assigned to the tC time
      tC=r0[l-1].time;
      //--- check if tO has the correct value and modify if needed.
      while(tO>tC)
         tO-=PeriodSeconds();
      //--- the time values of tO and tC have actual meaning for the bar under formation  
      int index=len-1-cnt;
      rates[index].close=0;
      rates[index].open=0;
      rates[index].high=0;
      rates[index].low=0;
      rates[index].time=tO;
      for(int i=0; i<l; i++)
         if(r0[i].time>=tO && r0[i].time<=tC)
           {
            if(rates[index].open==0)
              {
               rates[index].open= r0[i].open;
               rates[index].low = r0[i].low;
               rates[index].high= r0[i].high;
                 }else{
               if(rates[index].low > r0[i].low)
                  rates[index].low=r0[i].low;
               if(rates[index].high < r0[i].high)
                  rates[index].high=r0[i].high;
              }
            rates[index].close=r0[i].close;
           }
      //--- specifying closing time of the next bar in the loop
      tC=tO-PeriodSeconds(base_period);
      //
      cnt++;
     }
   if(cnt<len)
     {
      //-- less data than required, move to the beginning of the buffer
      int d=len-cnt;
      for(int j=0; j<cnt; j++)
         rates[j]=rates[j+d];
      for(int j=cnt;j<len;j++)
        {
         //--- fill unused array elements with zeros
         rates[j].close=0;
         rates[j].open=0;
         rates[j].high=0;
         rates[j].low=0;
         rates[j].time=0;
        }
     }
   shift = sh;  
   return(cnt);
  }

重要なポイントはいくつか強調表示されています。

下図は『ファントムバー』例を示しています。このバーは10月27日の最初の分について形成され、10月26日23:01 の開始時刻のバーに含まれてしまいました。そのようなバーの後、インディケータチャートはソースチャートとの関係で左に移動します。最初の時刻(たとえば21:00 →21:01)に対応するそのバーは異なるインデックスを持つことになります。

ファントムバー

図4 2014.10.26 23:01 のファントムバー


3. インディケータの実装

個別のウィンドウに『リキッドチャート』を表示するインディケータを書きます。インディケータは3とおりのモードすべてで動作します。:静的シフトモード、動的シフトバー開始モード、動的シフトバー終了モードです。インディケータはまたインディケータパラメータダイアログを呼ぶことなくモードとシフト値を変更する制御エレメントを持つ必要があります。

まずF liquidchart.mqh ファイルから GetRatesLC() 関数を使います。それを RefreshBuffers() 関数から呼びます。それはOnCalculate 関数から呼ばれる関数です。モードまたはシフトの変更とインディケータバッファの再計算が必要であれば、それは OnChartEventから呼ぶこともできます。OnChartEvent 関数はボタンを押すこととシフトとモードの値の変更を処理します。

以下がインディケータの入力パラメータです。

input ENUM_TIMEFRAMES   BaseTF=PERIOD_M1;       // LC Base Period
input int               Depth=100;              // Depth, bars
input ENUM_LC_MODE      inp_LC_mode=LC_MODE_SS; // LC mode
input int               inp_LC_shift=0;         // LC shift

ここで Depth は結果チャートのバー数、ENUM_LC_MODE はインディケータのプロットモードを述べるタイプです。

enum ENUM_LC_MODE
  {//plotting mode
   LC_MODE_SS=0,  // Static Shift
   LC_MODE_DSO=1, // Dynamic Shift, just Open
   LC_MODE_DSC=2  // Dynamic Shift, expected Close
  };
パラメータ inp_LC_mode および inp_LC_shift はそれぞれ LC_modeLC_shift によってコピーされます。この設計によりボタンを押すことでその値を変更することができるのです。ボタンを描画することとボタンの押下処理については本稿のトピックに関連がないため取り上げません。RefreshBuffers() 関数を詳しく考察します。
bool RefreshBuffers(int total,
                    double &buff1[],
                    double &buff2[],
                    double &buff3[],
                    double &buff4[],
                    double &col_buffer[])
  {
   MqlRates rates[];
   ArrayResize(rates,Depth);
//---
   int copied=0;
   int shift=0;
   if(LC_mode==LC_MODE_SS)
      shift = LC_shift; //static shift
   else if(LC_mode==LC_MODE_DSO)
      shift = -1;       //calculate shift (beginning of the bar formation)
   else if(LC_mode==LC_MODE_DSC)
      shift = -2;       //calculate shift (end of the bar formation)
   else
      return(false);
//---
   copied=GetRatesLC(0,Depth,rates,BaseTF,shift);
//---
   if(copied<=0)
     {
      Print("No data");
      return(false);
     }
   LC_shift = shift;
   refr_keys();
//--- initialize buffers with empty values
   ArrayInitialize(buff1,0.0);
   ArrayInitialize(buff2,0.0);
   ArrayInitialize(buff3,0.0);
   ArrayInitialize(buff4,0.0);
//---
   int buffer_index=total-copied;
   for(int i=0;i<copied;i++)
     {
      buff1[buffer_index]=rates[i].open;
      buff2[buffer_index]=rates[i].high;
      buff3[buffer_index]=rates[i].low;
      buff4[buffer_index]=rates[i].close;
      //---
      if(rates[i].open<=rates[i].close)
         col_buffer[buffer_index]=1;//bullish or doji
      else
         col_buffer[buffer_index]=0;//bearish
      //
      buffer_index++;
     }
//
   return(true);
  }

まず shift 変数に関連する値がモードに応じてGetRatesLC() 関数に渡されます。静的モードではそれはLC_shift パラメータのコピーで、それに応じてバーの開始または終了モードでは -1~ -2 となります。関数が正常に実行されたら、GetRatesLC() が、 shift 変数に対してシフトの現在の値を返します。それは再計算されるかそのままかどちらかです。いずれにしても、その値を LC_shift 変数に割り当て、それから refr_keys() 関数によってグラフィックエレメントの再作成を呼びます。

その後、インディケータバッファの OHLC 値とバーの色を更新します。

インディケータのフルコードは liquid_chart.mq5 ファイルにあります。起動後、インディケータは以下のようになります。

リキッドチャートインディケータ、シフト 0

図5 リキッドチャートインディケータ

制御エレメントについて少し説明します。

SS モードでは、シフト値 0 のとき、インディケータは最初のチャートの値をコピーしています。シフト値を変更すれば、チャートが再作成されるのがわかります。顕著な違いはすでに値 28 で現れます。弱い "rails" の代わりに目立った "hammer" が存在します。これは買いのタイミングでしょうか?

リキッドチャートインディケータ、シフト 28

図6 リキッドチャートインディケータ、シフト 28

インディケータを DSO モードに切り替えると新たに形成されるバーがつねに右にきます。DSC モードでは基本タイムフレーム値内でクローズするバーが存在します。


4. エキスパートの作成

エキスパートを2件作成します。一番目は「移動平均」によってトレードを行うもの、二番目は「ピンバー」パターンによってトレードを行うものです。

テンプレートとしての標準的な例(Experts\Examples\Moving Average フォルダ)から 移動平均エキスパートを取ります 。静的シフトまたは動的シフトを使用するとき関連性といくばくかの有意性があることを理解するために、このように基本的に異なる2件の戦略の最適化結果を比較しすることができます。


4.1. 移動平均を用いたエキスパートのトレーディング

ます入力パラメータを決定します。入力パラメータは4個あります。

input double MaximumRisk    = 0.1// Maximum Risk in percentage
input double DecreaseFactor = 3;    // Decrease factor
input int    MovingPeriod   = 12;   // Moving Average period
input int    MovingShift    = 6;    // Moving Average shift

近代化後あと3個のパラメータを追加します。

input ENUM_TIMEFRAMES  BaseTF=PERIOD_M1;  // LC Base Period
input bool             LC_on = true;      // LC mode ON
input int              LC_shift = 0;      // LC shift

LC_on パラメータは GetRatesLC() が正常に動作するか確認するのに有用です。コンビネーション (LC_on == true && LC_shift == 0)(LC_on == false) と同様の結果となるはずです。

シフトを伴う既製エキスパートの移動平均を近代化するには、シフト機能が有効となっているとき(入力パラメータ LC_on)、liquidchart.mqhファイルをインクルードし、 CopyRates() 関数を GetRatesLC() で置き換える必要があります。

int copied;
   if(LC_on==true)
     {
      int shift = LC_shift;
      copied=GetRatesLC(0,2,rt,BaseTF,shift);
     }
   else
      copied = CopyRates(_Symbol,_Period,0,2,rt);
   if(copied!=2)
     {
      Print("CopyRates of ",_Symbol," failed, no history");
      return;
     }

それは関数 CheckForOpen() および CheckForClose() の両方で行う必要があります。インディケータハンドラは使用せず「移動平均」をマニュアルで計算します。そのために CopyMABuffer() 関数を追加しました。

int CopyMABuffer(int len,double &ma[])
  {
   if(len<=0)
      return(0);
   MqlRates rates[];
   int l=len-1+MovingPeriod;
   int copied;
   if(LC_on==true)
     {
      int shift = LC_shift;
      ArrayResize(rates,l);
      copied=GetRatesLC(MovingShift,l,rates,BaseTF,shift);
     }
   else
      copied=CopyRates(_Symbol,_Period,MovingShift,l,rates);
//      
   if(copied<l)
      return(0);
//
   for(int i=0;i<len;i++)
     {
      double sum=0;
      for(int j=0;j<MovingPeriod;j++)
        {
         if(LC_on==true)
            sum+=rates[j+i].close;
         else
            sum+=rates[copied-1-j-i].close;
        }
      ma[i]=sum/MovingPeriod;
     }
   return(len);
  }

それはなんらかの理由で取得に失敗した場合、必要な値の数値または ma[] バッファ内の 0 を返します。

開始バーの制御は考慮すべきもう一つ別の重要ポイントです。オリジナルバージョンの 移動平均 Expert Advisor ではそれはティック値によって取り入れられています。

if(rt[1].tick_volume>1)
      return;

われわれの場合、ティックボリュームはないのでバー開始を制御するために newbar() 関数を書きます。

bool newbar(datetime t)
  {
   static datetime t_prev=0;
   if(t!=t_prev)
     {
      t_prev=t;
      return(true);
     }
   return(false);
  }

処理の原則はバーの開始時億を前回の値と比較することです。関数CheckForOpen() および CheckForClose()内で newbar()を呼ぶためのティックボリュームの確認を置き換えます。

if(newbar(rt[1].time)==false)
      return;

既製英気スパートのコード完全版は moving_average_lc.mq5 ファイルにあります。


4.2. 「ピンバー」パターンによってトレードを行うExpert Advisor

ピンバー または ピノキオバー は3本のバーで構成されるパターンです。真ん中のバーは長いヒゲまたは『鼻』を持ち、価格変動の可能性ある反転を示しています。両側のバーは『目』と呼ばれます。その端点は近隣バーのヒゲより長くなりません。このパターンはろうそく足モデルでトレードを行うトレーダーの間で人気です。

われわれのピンバーは以下の価格下降の反転条件を満たす必要があります。

パターンのチェックは r[3] バーの開始時に行われます。

ピンバー

図7 「ピンバー」パターン

以下が下向きの反転に対するピンバーの存在を決定するコードです。

if(r[0].open<r[0].close && r[2].open>r[2].close && r[1].high>MathMax(r[0].high,r[2].high))
     {
     //--- eyes of the upper pin bar
      double oc=MathAbs(r[1].open-r[1].close)/_Point;
      if(oc>inp_pb_max_OC)
         return(0);
      double shdw=(r[1].high-MathMax(r[1].open,r[1].close))/_Point;
      if(shdw<inp_pb_min_shdw)
         return(0);
      if(oc!=0)
        {
         if((shdw/oc)<inp_pb_min_ratio)
            return(0);
        }
      return(1);
     }

上向きの反転と同様です。したがってピンバーの存在を確認する関数は以下のように記述されます。

int IsPinbar(MqlRates &r[])
  {
   //--- there must be 4 values in the r[] array
   if(ArraySize(r)<4)
      return(0);
   if(r[0].open<r[0].close && r[2].open>r[2].close && r[1].high>MathMax(r[0].high,r[2].high))
     {
      //--- eyes of the upper pin bar
      double oc=MathAbs(r[1].open-r[1].close)/_Point;
      if(oc>inp_pb_max_OC)
         return(0);
      double shdw=(r[1].high-MathMax(r[1].open,r[1].close))/_Point;
      if(shdw<inp_pb_min_shdw)
         return(0);
      if(oc!=0)
        {
         if((shdw/oc)<inp_pb_min_ratio)
            return(0);
        }
      return(1);
     }
   else if(r[0].open>r[0].close && r[2].open<r[2].close && r[1].low<MathMin(r[0].low,r[2].low))
     {
      //--- eyes of the lower pin bar
      double oc=MathAbs(r[1].open-r[1].close)/_Point;
      if(oc>inp_pb_max_OC)
         return(0);
      double shdw=(MathMin(r[1].open,r[1].close)-r[1].low)/_Point;
      if(shdw<inp_pb_min_shdw)
         return(0);
      if(oc!=0)
        {
         if((shdw/oc)<inp_pb_min_ratio)
            return(0);
        }
      return(-1);
     }
   return(0);
  }

渡される履歴データの配列は4エレメント以上です。上のピンバーが検出される場合(それは下向きの反転を示すピンバーです)、関数は値1を返します。低いピンバーがある倍(上向きの反転と想定される)、関数は値 -1 を返します。ピンバーがまったく存在しない場合、この関数は 0 を返します。またこの関数は次の入力パラメータを使用します。

input uint   inp_pb_min_shdw     = 40;    // Pin bar min shadow, point
input uint   inp_pb_max_OC       = 20;    // Pin bar max OC, point
input double inp_pb_min_ratio    = 2.0;   // Pin bar shadow to OC min ratio

われわれはピンバーによるもっともシンプルな戦略でトレードをしようとしています。下向きの反転が予想されると売り、上向きの反転だと買いを行います。通常、インディケータ確認が必要ですが、今回はそれは行わず実験的整合性を維持します。われわれはピンバーのみを使用します。

「ピンバー」パターンによる Expert Advisor のトレーディングは「移動平均」によるエキスパートトレーディングに基づいています。CopyMABuffer() 関数は後者から削除します。関数 CheckForOpen() および CheckForClose() からのこの関数の呼び出しも同様です。依頼される履歴データ数は2から4に増えることとなります。 r[3] バー時刻は新規バー開始確認に使用されます。

int copied;
   if(LC_on==true)
   {
      int shift = LC_shift;
      copied=GetRatesLC(0,4,rt,BaseTF,shift);
   }
   else
      copied = CopyRates(_Symbol,_Period,0,4,rt);
   if(copied!=4)
     {
      Print("CopyRates of ",_Symbol," failed, no history");
      return;
     }
   if(newbar(rt[3].time)==false)
      return;

以下はポジションオープンのシグナル確認です。

int pb=IsPinbar(rt);
   if(pb==1)       // upper pin bar
      signal=ORDER_TYPE_SELL; // sell conditions
   else if(pb==-1) // lower pin bar
      signal=ORDER_TYPE_BUY// buy conditions

次は反対側のピンバーによるポジションのクローズです。

if(type==(long)POSITION_TYPE_BUY && pb==1)
      signal=true;
   if(type==(long)POSITION_TYPE_SELL && pb==-1)
      signal=true;

入力パラメータの厳しい条件ではピンバー seldom が発生することに留意ください。このため反対側のピンバーによってのみポジションがクローズするとき、利益を失うか、損失で終了するリスクがあります。

これに関連してテイクプロフィットストップロスレベルを追加します。それらは外部パラメータ inp_tp_pp inp_sl_pp によってそれぞれ設定されます。

double sl=0,tp=0,p=0;
   double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
   double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
   if(signal==ORDER_TYPE_SELL)
   {
     p=bid;
     if(inp_sl_pp!=0)
       sl=NormalizeDouble(ask+inp_sl_pp*_Point,_Digits);
     if(inp_tp_pp!=0)
       tp=NormalizeDouble(ask-inp_sl_pp*_Point,_Digits);
   } else {
     p=ask;
     if(inp_sl_pp!=0)
       sl=NormalizeDouble(bid-inp_sl_pp*_Point,_Digits);
     if(inp_tp_pp!=0)
       tp=NormalizeDouble(bid+inp_sl_pp*_Point,_Digits);
   }
   CTrade trade;
   trade.PositionOpen(_Symbol,signal,TradeSizeOptimized(),p,sl,tp);

inp_tp_pp または inp_sl_pp の値がゼロであれば、対応するテイクプロフィット または ストップロス の値は設定されません。

変更は完了しました。エキスパートは準備できました。コードの完全版は pinbar_lc.mq5 ファイルにあります。


5. エキスパートの最適化

ことなる戦略でシフトを伴うチャートの有効性を評価するには、最良結果をさらに比較することでエキスパートの最適化を利用します。もっとも重要なパラメータは収益、ドローダウン、トレード数です。移動平均でトレードを行うExpert Advisor はインディケータ戦略の役目をし、「ピンバー」パターンによってトレードを行うエキスパートは非インディケータ戦略ケースを代表します。

最適化は MetaQuotes-Demo サーバーから1年の後半についてのクオートにより実行されます。この実験はEURUSD、GBPUSD、USDJPY に対して行われます。開始デポジットはレバレッジ 1:100 の 3,000 米ドルです。テストモードは『全ティック』です。最適化モード-速い(遺伝的アルゴリズム)、バランスマックス



5.1. 移動平均を用いたエキスパートのトレーディングの最適化結果分析

異なるモードで動作しているときのエキスパートの最適化結果を比較します。シフトゼロ、静的シフト、動的シフト(DSODSC)のモードです。

テストは期間 2014.04.01~ 2014.10.25(過去半年)、EURUSD、 GBPUSD、USDJPYについて行います。期間 H1

エキスパートの入力パラメータ

パラメータ
最大リスク(パーセント表示) 0.1
減少率 3.0
移動平均期間 12
移動平均シフト 6
ベースTF 1 分
LC_on
LC_shift 0

表3 移動平均 LC エキスパートの入力パラメータ


5.1.1. 無効シフトモードでのエキスパート最適化

最適化されたパラメータ

パラメータ 開始 ステップ 終了
移動平均期間 12 1 90
移動平均シフト 6 1 30

表4 ゼロシフトモードにおける移動平均 LC エキスパートの最適化されたパラメータ

シフトモード無効でのエキスパート最適化を示すグラフ:EURUSD

ゼロシフトモードにおける最適化:EURUSD

図8 ゼロシフトモードにおける移動平均 LC エキスパートの最適化:EURUSD

最良結果

結果 収益 ドローダウン % トレード数 MovingPeriod MovingShift
3796,43 796,43 16,18 111 24 12
3776,98 776,98 17,70 77 55 22
3767,45 767,45 16,10 74 59 23
3740,38 740,38 15,87 78 55 17
3641,16 641,16 15,97 105 12 17

表5 ゼロシフトモードにおける移動平均 LC エキスパートの最良結果

ゼロシフトモードでのエキスパート最適化を示すグラフ:GBPUSD

ゼロシフトモードにおける最適化:GBPUSD

図9 ゼロシフトモードにおける移動平均 LC エキスパートの最適化:GBPUSDD

最良結果

結果 収益 ドローダウン % トレード数 MovingPeriod MovingShift
4025,75 1025,75 8,08 80 18 22
3857,90 857,90 15,04 74 55 13
3851,40 851,40 18,16 80 13 24
3849,48 849,48 13,05 69 34 29
3804,70 804,70 16,57 137 25 8

表6 GBPUSDについてゼロシフトモードにおける移動平均 LC エキスパートの最良結果

USDJPY についてシフトモード無効でのエキスパート最適化を示すグラフ

ゼロシフトモードにおける最適化:USDJPY

図10 ゼロシフトモードにおける移動平均 LC エキスパートの最適化:USDJPY

最良結果

結果 収益 ドローダウン % トレード数 MovingPeriod MovingShift
5801,63 2801,63 11,54 48 65 23
5789,17 2789,17 14,03 50 44 27
5539,06 2539,06 17,14 46 67 27
5331,34 2331,34 15,05 61 70 9
5045,19 2045,19 12,61 48 83 15

表7 USDJPY についてゼロシフトモードにおける移動平均 LC エキスパートの最良結果


5.1.2. 静的シフトモードでのエキスパート最適化

最適化されたパラメータ

パラメータ 開始 ステップ 終了
移動平均期間 12 1 90
移動平均シフト 6 1 30
LC_shift 1 1 59

表8 静的シフトモードにおける移動平均 LC エキスパートの最適化されたパラメータ

EURUSD について静的シフトモードでのエキスパート最適化を示すグラフ

静的シフトモードにおける最適化:EURUSD

図11 静的シフトモードにおける移動平均 LC エキスパートの最適化:EURUSD

最良結果

結果 収益 ドローダウン % トレード数 MovingPeriod MovingShift LC_shift
4385,06 1385,06 12,87 100 32 11 8
4149,63 1149,63 14,22 66 77 25 23
3984,92 984,92 21,52 122 12 11 26
3969,35 969,35 16,08 111 32 11 24
3922,95 922,95 12,29 57 77 25 10

表9 EURUSD について静的シフトモードにおける移動平均 LC エキスパートの最良結果

GBPUSD について静的シフトモードでのエキスパート最適化を示すグラフ

静的シフトモードにおける最適化:GBPUSD

図12 静的シフトモードにおける移動平均 LC エキスパートの最適化:GBPUSD

最良結果

結果 収益 ドローダウン % トレード数 MovingPeriod MovingShift LC_shift
4571,07 1571,07 14,90 79 12 25 42
4488,90 1488,90 15,46 73 12 25 47
4320,31 1320,31 9,59 107 12 16 27
4113,47 1113,47 10,96 75 12 25 15
4069,21 1069,21 15,27 74 12 25 50

表10 GBPUSD について静的シフトモードにおける移動平均 LC エキスパートの最良結果

USDJPY について静的シフトモードでのエキスパート最適化を示すグラフ

静的シフトモードにおける最適化:USDJPY

図13 静的シフトモードにおける移動平均 LC エキスパートの最適化:USDJPY

最良結果

結果 収益 ドローダウン % トレード数 MovingPeriod MovingShift LC_shift
6051,39 3051,39 15,94 53 76 12 31
5448,98 2448,98 10,71 54 44 30 2
5328,15 2328,15 11,90 50 82 13 52
5162,82 2162,82 10,46 71 22 26 24
5154,71 2154,71 14,34 54 75 14 58

表11 USDJPY について静的シフトモードにおける移動平均 LC エキスパートの最良結果


5.1.3. 動的シフトモードでのエキスパート最適化

最適化されたパラメータ

パラメータ 開始 ステップ 終了
移動平均期間 12 1 90
移動平均シフト 6 1 30
LC_shift -2 1 -1

表12 動的シフトモードにおける移動平均 LC エキスパートの最適化されたパラメータ

EURUSD について動的シフトモードでのエキスパート最適化を示すグラフ

動的シフトモードにおける最適化:EURUSD

図14 動的シフトモードにおける移動平均 LC エキスパートの最適化:EURUSD

最良結果

結果 収益 ドローダウン % トレード数 MovingPeriod MovingShift LC_shift
3392,64 392,64 27,95 594 15 13 -2
3140,26 140,26 23,35 514 12 17 -2
2847,12 -152,88 17,04 390 79 23 -1
2847,12 -152,88 17,04 390 79 12 -1
2826,25 -173,75 20,12 350 85 22 -1

表13 EURUSD について動的シフトモードにおける移動平均 LC エキスパートの最良結果

GBPUSD について動的シフトモードでのエキスパート最適化を示すグラフ

動的シフトモードにおける最適化:GBPUSD

図15 動的シフトモードにおける移動平均 LC エキスパートの最適化:GBPUSD

最良結果

結果 収益 ドローダウン % トレード数 MovingPeriod MovingShift LC_shift
5377,58 2377,58 19,73 391 12 26 -2
3865,50 865,50 18,18 380 23 23 -2
3465,63 465,63 21,22 329 48 21 -2
3428,99 428,99 24,55 574 51 16 -1
3428,99 428,99 24,55 574 51 15 -1

表14 GBPUSD について動的シフトモードにおける移動平均 LC エキスパートの最良結果

USDJPY について動的シフトモードでのエキスパート最適化を示すグラフ

動的シフトモードにおける最適化:USDJPY

図16 USDJPYシフトモードにおける移動平均 LC エキスパートの最適化:USDJPY

最良結果

結果 収益 ドローダウン % トレード数 MovingPeriod MovingShift LC_shift
6500,19 3500,19 17,45 244 42 28 -2
6374,18 3374,18 19,91 243 54 24 -2
6293,29 3293,29 19,30 235 48 27 -2
5427,69 2427,69 17,65 245 90 8 -2
5421,83 2421,83 16,30 301 59 12 -2

表15 USDJPY について動的シフトモードにおける移動平均 LC エキスパートの最良結果


5.2. 「ピンバー」パターンを用いたエキスパートのトレーディングの最適化結果分析

異なるモードで動作しているときのエキスパートの最適化結果を比較します。シフトゼロ、静的シフト、動的シフト(DSODSC)のモードです。テストは期間 2014.04.01~ 2014.10.25、EURUSD、 GBPUSD、USDJPYについて行います。期間 H1

エキスパートの入力パラメータ

パラメータ
最大リスク(パーセント表示) 0.1
減少要因 3.0
ピンバー最小ヒゲ、ポイント 40
ピンバー最大OC、ポイント 110
OC 最小比率に対するピンバーのヒゲ 1.4
SL、ポイント(0 または OFF) 150
TP、ポイント(0 または OFF) 300
LC ベース期間 1 分
LC モードオン
LC シフト 0

表16 ピンバー LC エキスパートの入力パラメータ

ピンバーの形を決定しながらパラメータの最適化を行います。:『鼻』の長さ、真ん中のバー本体に対する『鼻』の長さの比率、本体の最大サイズです。テイクプロフィット および ストップロス レベルも最適化されます。


5.2.1. 無効シフトモードでのエキスパート最適化

最適化されたパラメータ

パラメータ 開始 ステップ 終了
ピンバー最小ヒゲ、ポイント 100 20 400
ピンバー最大OC、ポイント 20 20 100
OC 最小比率に対するピンバーのヒゲ 1 0.2 3
SL、ポイント(0 または OFF) 150 50 500
TP、ポイント(0 または OFF) 150 50 500

表17 シフトモード無効でのピンバー LC エキスパートの最適化されたパラメータ

シフトモード無効でのエキスパート最適化を示すグラフ:EURUSD

ゼロシフトでの最適化:EURUSD

図17 ゼロシフトモードにおけるピンバー LC エキスパートの最適化:EURUSD

最良結果

結果 収益 ドローダウン % トレード数 ピンバー最小ヒゲ ピンバー最大OC ピンバーヒゲ対 OC 最小比率 SL TP
3504,59 504,59 9,82 33 100 60 1.8 450 500
3428,89 428,89 8,72 21 120 60 2.8 450 350
3392,37 392,37 9,94 30 100 60 2,6 450 250
3388,54 388,54 9,93 31 100 80 2,2 450 300
3311,84 311,84 6,84 13 140 60 2,2 300 450

表18 EURUSD についてゼロシフトモードにおけるピンバー LC エキスパートの最良の最適化結果

ゼロシフトモードでのエキスパート最適化を示すグラフ:GBPUSD

ゼロシフトでの最適化:GBPUSD

図18 ゼロシフトモードにおけるピンバー LC エキスパートの最適化:GBPUSD

最良結果

結果 収益 ドローダウン % トレード数 ピンバー最小ヒゲ ピンバー最大OC ピンバーヒゲ対 OC 最小比率 SL TP
3187,13 187,13 11,10 13 160 60 2,6 500 350
3148,73 148,73 3,23 4 220 40 2,8 400 400
3142,67 142,67 11,27 17 160 100 1,8 500 350
3140,80 140,80 11,79 13 180 100 2 500 500
3094,20 94,20 1,62 1 260 60 1,6 500 400

表19 GBPUSD についてゼロシフトモードにおけるピンバー LC エキスパートの最良の最適化結果

USDJPY についてシフトモード無効でのエキスパート最適化を示すグラフ

ゼロシフトでの最適化:EURUSD

図19 ゼロシフトモードにおけるピンバー LC エキスパートの最適化:USDJPY

最良結果

結果 収益 ドローダウン % トレード数 ピンバー最小ヒゲ ピンバー最大OC ピンバーヒゲ対 OC 最小比率 SL TP
3531,99 531,99 9,00 6 160 60 2.2 450 500
3355,91 355,91 18,25 16 120 60 1,6 450 400
3241,93 241,93 9,11 4 160 40 2,8 450 500
3180,43 180,43 6,05 33 100 80 1,8 150 450
3152,97 152,97 3,14 6 160 80 2,8 150 500

表20 USDJPY についてゼロシフトモードにおけるピンバー LC エキスパートの最良の最適化結果


5.2.2. 静的シフトモードでのエキスパート最適化

最適化されたパラメータ

パラメータ 開始 ステップ 終了
ピンバー最小ヒゲ、ポイント 100 20 400
ピンバー最大OC、ポイント 20 20 100
OC 最小比率に対するピンバーのヒゲ 1 0.2 3
SL、ポイント(0 または OFF) 150 50 500
TP、ポイント(0 または OFF) 150 50 500
LC シフト 1 1 59

表21 静的シフトモードでのピンバー LC エキスパートの最適化されたパラメータ

EURUSD について静的シフトモードでのエキスパート最適化を示すグラフ

静的シフトモードにおける最適化:EURUSD

図20 静的シフトモードにおけるピンバー LC エキスパートの最適化:EURUSD

最良結果

結果 収益 ドローダウン % トレード数 ピンバー最小ヒゲ ピンバー最大OC ピンバーヒゲ対 OC 最小比率 SL TP LC シフト
4843,54 1843,54 10,14 19 120 80 1,6 500 500 23
4714,81 1714,81 10,99 28 100 100 1,6 500 500 23
4672,12 1672,12 10,16 18 120 80 1,8 500 500 23
4610,13 1610,13 9,43 19 120 80 1,6 450 450 23
4562,21 1562,21 13,94 27 100 100 1,6 500 400 25

表22 EURUSD について静的シフトモードにおけるピンバー LC エキスパートの最良の最適化結果

GBPUSD について静的シフトモードでのエキスパート最適化を示すグラフ

静的シフトモードにおける最適化:GBPUSD

図21 静的シフトモードにおけるピンバー LC エキスパートの最適化:GBPUSD

最良結果

結果 収益 ドローダウン % トレード数 ピンバー最小ヒゲ ピンバー最大OC ピンバーヒゲ対 OC 最小比率 SL TP LC シフト
4838,10 1838,10 5,60 34 100 40 2,4 450 500 24
4797,09 1797,09 5,43 35 100 40 2,6 400 500 24
4755,57 1755,57 7,36 42 100 100 2 400 500 24
4725,41 1725,41 8,35 45 100 80 1 400 500 24
4705,61 1705,61 8,32 41 100 100 2 450 500 24

表23 GBPUSD について静的シフトモードにおけるピンバー LC エキスパートの最良の最適化結果

USDJPY について静的シフトモードでのエキスパート最適化を示すグラフ

静的シフトモードにおける最適化:USDJPY

図22 静的シフトモードにおけるピンバー LC エキスパートの最適化:USDJPY

最良結果

結果 収益 ドローダウン % トレード数 ピンバー最小ヒゲ ピンバー最大OC ピンバーヒゲ対 OC 最小比率 SL TP LC シフト
4108,83 1108,83 6,45 9 140 40 1,4 500 450 55
3966,74 966,74 7,88 12 140 60 2,8 450 500 45
3955,32 955,32 9,91 21 120 80 2 500 500 45
3953,80 953,80 6,13 10 140 60 2,8 450 450 47
3944,33 944,33 6,42 6 160 100 2,6 500 400 44

表24 USDJPY について静的シフトモードにおけるピンバー LC エキスパートの最良の最適化結果


5.2.3. 動的シフトモードでのエキスパート最適化

最適化されたパラメータ

パラメータ 開始 ステップ 終了
ピンバー最小ヒゲ、ポイント 100 20 400
ピンバー最大OC、ポイント 20 20 100
OC 最小比率に対するピンバーのヒゲ 1 0.2 3
SL、ポイント(0 または OFF) 150 50 500
TP、ポイント(0 または OFF) 150 50 500
LC シフト -2 1 -1

表25 動的シフトモードでのピンバー LC エキスパートの最適化されたパラメータ

EURUSD について動的シフトモードでのエキスパート最適化を示すグラフ

動的シフトモードにおける最適化:EURUSD

図23 動的シフトモードにおけるピンバー LC エキスパートの最適化:EURUSD

最良結果

結果 収益 ドローダウン % トレード数 ピンバー最小ヒゲ ピンバー最大OC ピンバーヒゲ対 OC 最小比率 SL TP LC シフト
4185,65 1185,65 13,22 49 200 100 1,8 450 500 -2
4011,80 1011,80 13,75 49 200 100 2 400 500 -2
3989,28 989,28 12,01 76 140 20 1,2 350 200 -1
3979,50 979,50 16,45 157 100 20 1 450 500 -1
3957,25 957,25 16,68 162 100 20 1 400 500 -1

表26 EURUSD について静的シフトモードにおけるピンバー LC エキスパートの最良の最適化結果

GBPUSD について動的シフトモードでのエキスパート最適化を示すグラフ

動的シフトモードにおける最適化:GBPUSD

図24 動的シフトモードにおけるピンバー LC エキスパートの最適化:GBPUSD

最良結果

結果 収益 ドローダウン % トレード数 ピンバー最小ヒゲ ピンバー最大OC ピンバーヒゲ対 OC 最小比率 SL TP LC シフト
4906,84 1906,84 10,10 179 120 40 1,8 500 500 -2
4316,46 1316,46 10,71 151 120 20 2,4 450 500 -1
4250,96 1250,96 12,40 174 120 40 1,8 500 500 -1
4040,82 1040,82 12,40 194 120 60 2 500 200 -2
4032,85 1032,85 11,70 139 140 40 2 400 200 -1

表27 GBPUSD について動的シフトモードにおけるピンバー LC エキスパートの最良の最適化結果

USDJPY について動的シフトモードでのエキスパート最適化を示すグラフ

動的シフトモードにおける最適化:USDJPY

図25 動的シフトモードにおけるピンバー LC エキスパートの最適化:USDJPY

最良結果

結果 収益 ドローダウン % トレード数 ピンバー最小ヒゲ ピンバー最大OC ピンバーヒゲ対 OC 最小比率 SL TP LC シフト
5472,67 2472,67 13,01 138 100 20 2,4 500 500 -1
4319,84 1319,84 15,87 146 100 20 2,2 400 500 -1
4259,54 1259,54 19,71 137 100 20 2,4 500 500 -2
4197,57 1197,57 15,98 152 100 20 1 350 500 -1
3908,19 908,19 16,79 110 120 40 3 400 400 -1

表28 USDJPY について動的シフトモードにおけるピンバー LC エキスパートの最良の最適化結果


6. 最適化結果の比較

比較表を作成するには、収益、ドローダウン、トレード数最大値を最良結果の表それぞれから選びます。静的または動的シフトモードで受け取られた値の次に変化(パーセント表記)またはゼロシフトモードにおける同じ値との関連でこの値を記載します。


6.1. 移動平均を用いたエキスパートのトレーディング

収益

シフトなし 静的シフト 動的シフト
EURUSD 796,43 1385,06 (+74%) 392,64 (-51%)
GBPUSD 1025,75 1571,07 (+53%) 2377,58 (+132%)
USDJPY 2801,63 3051,39 (+9%) 3500,19 (+25%)

表29 移動平均LC エキスパートの最良の最適化結果表からの最大収益値比較

ドローダウン

シフトなし 静的シフト 動的
シフトt
EURUSD 17,7 21,52 (+22%) 27,95 (+58%)
GBPUSD 18,16 15,46 (-15%) 24,55 (+35%)
USDJPY 17,14 15,94 (-7%) 19,91 (+16%)

表30 移動平均LC エキスパートの最良の最適化結果表からの最大ドローダウン値比較

トレード数

シフトなし 静的シフト 動的シフト
EURUSD 111 122 (+10%) 594 (+435%)
GBPUSD 137 107 (-22%) 574 (+319%)
USDJPY 61 71 (+16%) 301 (+393%)

表31 移動平均LC エキスパートの最良の最適化結果表からの最大トレード数値比較

最初に目が引かれるのは動的シフトモードにおけるエントリーポイントの大幅な増加です。同時に、ドローダウンは目だって増加していますが、収益は EURUSD については2倍減少しています。

指摘シフトモードはこの Expert Advisor に対してはより収益性があります。ここで GBPUSD と USDJPY に対するドローダウンが下がっているのと、EURUSD と GBPUSD に対して収益が著しく増えているのがわかります。


6.2. 「ピンバー」パターンによるエキスパートのトレード

収益

シフトなし 静的シフト 動的シフト
EURUSD 504,59 1843,54 (+265%) 1185,65 (+135%)
GBPUSD 187,13 1838,10 (+882%) 1906,84 (+919%)
USDJPY 531,99 1108,83 (+108%) 2472,67 (+365%)

表32 ピンバーLC エキスパートの最良の最適化結果表からの最大収益値比較

ドローダウン

シフトなし 静的シフト 動的シフト
EURUSD 9,94 13,94 (+40%) 16,68 (+68%)
GBPUSD 11,79 8,35 (-29%) 12,4 (+5%)
USDJPY 18,25 9,91 (-46%) 19,71 (+8%)

表33 ピンバーLC エキスパートの最良の最適化結果表からの最大ドローダウン値比較

トレード数

シフトなし 静的シフト 動的シフト
EURUSD 33 28 (-15%) 162 (+391%)
GBPUSD 17 45 (+165%) 194 (+1041%)
USDJPY 33 21 (-36%) 152 (+361%)

表34 ピンバーLC エキスパートの最良の最適化結果表からの最大トレード数値比較

ここでも動的シフトモードにおけるトレード数の大幅な増加が認められます。この場合はしかし、移動平均 LC エキスパートの場合に類似したドローダウンの大きな増加が EURUSD にのみあります。その他の通貨ペアに対しては、ドローダウンは約5~8%とわずかに増加しています。

静的シフトモードでは、最適化は GBPUSD と USDJPY に限られた収益を示しています。それでもなお、同じ通貨ペアに対して大きなドローダウンの減少が見られ、EURUSD には増加がみられます。静的シフトモードはこの Expert Advisor にとっては収益性が低いようです。


おわりに

本稿では『リキッドチャート』のプロット原則を考察し、その処理モードがインディケータおよび非インディケータ戦略を基にしたエキスパートの最適化結果に与える影響を比較しました。

そこで以下の結論が導かれます。