English Deutsch
preview
ボラティリティベースの取引システムの構築と最適化の方法(チャイキンボラティリティ - CHV)

ボラティリティベースの取引システムの構築と最適化の方法(チャイキンボラティリティ - CHV)

MetaTrader 5トレーディング | 4 6月 2024, 08:54
160 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

はじめに

取引の領域では、ボラティリティは非常に重要な要素であることが知られており、この要素を測定するために使用できるツールは数多くあります。そして、測定内容に応じて、ボラティリティを取引システムの一部として考慮すれば、より適切な取引決定を下すことができます。

今回は、このボラティリティテクニカル指標の1つであるチャイキンボラティリティ(CHV)を取り上げます。この記事を通して、チャイキンボラティリティについて何が重要なのか、それが何を意味するのか、どのように計算することができるのか、そして、より良い取引結果を得るためにどのように有利に使用することができるのかを学ぶことができます。簡単な取引戦略(CHVクロスオーバー、CHVとMAのクロスオーバー)に基づき、指標を使用します。

ここでのアプローチは、チャイキンボラティリティ指標をボラティリティツールとしてどのように考えれば、取引システムの一部となるボラティリティ測定において信頼できる、より良い取引結果を得ることができるかを理解することです。そこで、ボラティリティベース戦略に基づいて取引システムを構築する方法を学び、簡単な戦術を追加したり、他のツールを組み合わせたりして取引システムを最適化し、最適化しない場合に比べてより良い結果を得る方法を例示します。また、取引システムの一部として使用する独自のCHV指標の作成方法も学びます。

ご存知のように、どのような取引システムであっても、実際の取引に使用する前に、さまざまな環境でテストし、それが有用であり、ご自分の取引に適していることを確認することが非常に重要です。この2つの取引戦略に基づいて、取引システムの簡単なテストをおこなうことにします。この記事で私が使用したのとは異なる側面を使用してテストをおこない、私が得た結果よりも良い結果を得るためにご自分のシステムをどのように改善できるか、あるいは、このツールがご自分の取引システムにまったく適していないか適用できないかなどを確認することをお勧めします。

以下のトピックでは、次をすべてカバーします。

また、取引や一般的なプログラミングのためにコードを学ぶのであれば、自分で練習してコードを書くことが非常に重要であることも知っておく必要があります。プログラミングのスキルと知識を向上させるために、学んだことをコーディングすることをお勧めします。

免責条項:すべての情報は「現状有姿」で提供され、情報提供のみを目的としており、取引目的やアドバイスを目的としたものではありません。いかなる結果も保証するものではありません。読者がこれらの資料を自分の取引口座で使用する場合、自己責任でおこなってください。


チャイキンボラティリティ

この部分では、チャイキンボラティリティ指標(CHV)について詳しく説明します。チャイキンボラティリティはマーク・チャイキンによって作成されました。彼は、自分の名前を冠した多くのテクニカル指標を作成しました。CHVは、金融市場の動きのボラティリティを測定するために使用され、潜在的な市場の反転を予測するのに役立ちます。一定期間の高値と安値の間の値幅を決定し、潜在的な動きやどちらかの方向への市場の変動を測定するのに役立ちます。計算するときにわかるように、CHVではギャップを考慮していません。ボラティリティの上昇は、ハイリスクまたはハイリターンを意味し、その逆もまたしかりであることに注意することが非常に重要です。

CHV指標は高い値と低い値を記録することができます。値が上昇することは価格が非常に速く変化していることを意味しますが、低い値は価格が一定であり、原資産のボラティリティがあまりないことを意味します。言及するのが非常に重要だと思うのは、ボラティリティはトレンド市場だけでなく、トレンド市場でも非トレンド市場でも記録される可能性があるということです。測定しているのはボラティリティであり、価格のトレンドや方向ではないからです。生成されたものを確認するために使用できる他のテクニカルツールを使用すると、より良い結果が得られます。これは、前述のように、移動平均テクニカル指標を伴った決定を下して市場の方向性を示し、可能な限りトレンドの取引を行うように努めることです。

これまで述べてきたように、CHV指標は相場の反転を予測するために使用することができます。指標が比較的高い値を記録する場合、これを使用して市場の反転や潜在的な最高値または最低値を予測できます。ここで、CHV指標の背後にある主な概念についての認識を深めるために、CHV指標の算出方法を理解する必要があります。

H-L (i) = HIGH (i) - LOW (i)

H-L (i - 10) = HIGH (i - 10) - LOW (i - 10)

CHV = (EMA (H-L (i), 10) - EMA (H-L (i - 10), 10)) / EMA (H-L (i - 10), 10) * 100

ここで

  • HIGH (i):現在のローソク足の最高価格
  • LOW (i):現在のローソク足の最低価格
  • HIGH (i - 10):現在から10ポジション先までのローソク足の最高価格
  • LOW (i - 10):現在から10ポジション先までのローソク足の最低価格
  • H-L (i):現在のローソク足の最高価格と最低価格の差
  • H-L (i - 10):10本前の最高価格と最低価格の差
  • EMA:指数移動平均


カスタムチャイキンボラティリティ指標

このセクションでは、MQL5を使用してカスタムチャイキンボラティリティ指標をコーディングする方法を学びます。これは、目的に合わせて指標をカスタマイズできるので便利です。以下は、カスタムチャイキンボラティリティ(CHV)指標をコード化する手順です。

プリプロセッサ#includeを使用して、プログラムと計算で移動平均インクルードファイルを使用できるようにします。

#include <MovingAverages.mqh>

プリプロセッサ#propertyを使用して、以下の識別子値と同じパラメータを追加指定します。

  • description:MQL5プログラムの簡単なテキストを設定
  • indicator_separate_window:指標を別ウィンドウに表示
  • indicator_buffers:指標計算のためのバッファの数を設定
  • indicator_plots:指標のグラフィックシリーズの数を設定
  • indicator_type1:ENUM_DRAW_TYPEの値で指定されるグラフのプロットのタイプを指定(Nは図形系列の数で、1から始めることができる)
  • indicator_color1:行Nの表示色を指定(Nはグラフィックシリーズの数で、数字は1から始まる)
  • indicator_width1:指標の線の太さを指定(Nはグラフシリーズの数で、数字は1から始まる)
#property description "Chaikin Volatility"
#property indicator_separate_window
#property indicator_buffers 3

#property indicator_plots   1
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  MediumBlue
#property indicator_width1  3

enumキーワードを使用して移動平均平滑化モードのデータセットを定義します。

enum smoothMode
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };

inputキーワードを使用して指標設定の入力を設定します。

input int          smoothPeriodInp=10;  // Smoothing Period
input int          chvPeriodInp=10;     // Chaikin Volatility Period
input smoothMode InpSmoothType=EMA;   // Smoothing Mode

chv、hl、shlバッファの3つの配列を宣言します。

double             chvBuffer[];
double             hlBuffer[];
double             shlBuffer[];

平滑化期間とCHV期間のための2つのグローバル変数を宣言します。

int                smoothPeriod,chvPeriod;

OnInit()で、入力の変数を確認して指定します。

移動平均の名前:maNameを宣言した後、プログラムは入力がSMAかどうかを確認します。その場合名前はSMA(単純移動平均)になり、入力がEMAの場合はEMA(指数移動平均)になります。

   string maName;
   if(InpSmoothType==SMA)
      maName="SMA";
   else
      maName="EMA";

平滑化期間:プログラムは平滑化期間を確認し、それがゼロ以下であれば、デフォルト値の10を指定してメッセージを表示します。値が異なる場合、つまり10より大きい場合は、入力された値が与えられます。

   if(smoothPeriodInp<=0)
     {
      smoothPeriod=10;
      printf("Incorrect value for Smoothing Period input = %d. Default value = %d.",smoothPeriodInp,smoothPeriod);
     }
   else smoothPeriod=smoothPeriodInp;

CHV期間: CHV期間がゼロ以下であるかどうかが確認されます。値はデフォルトで10に設定され、メッセージが出力されます。異なる場合、つまり10より大きい場合は、入力された値が表示されます。

   if(chvPeriodInp<=0)
     {
      chvPeriod=10;
      printf("Incorrect value for Chaikin Volatility Period input = %d. Default value = %d.",chvPeriodInp,chvPeriod);
     }
   else chvPeriod=chvPeriodInp;

SetIndexBufferキーワードを使用して宣言されたバッファを定義し、ブール値を返します。パラメータは以下の通りです。

  • index:指標のバッファの番号(0から始まり、indicator_buffers識別子の#propertyの値より小さい)
  • buffer[]:カスタム指標で宣言された配列
  • data_type:保存する内容(chvBufferのデフォルトはINDICATOR_DATAであり、INDICATOR_CALCULATIONSは描画ではなく中間計算で使用するように指定する)
   SetIndexBuffer(0,chvBuffer);
   SetIndexBuffer(1,hlBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,shlBuffer,INDICATOR_CALCULATIONS);

描画設定を指定します。

   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,smoothPeriod+chvPeriod-1);
   PlotIndexSetString(0,PLOT_LABEL,"CHV("+string(smoothPeriod)+","+maName+")");
   IndicatorSetString(INDICATOR_SHORTNAME,"Chaikin Volatility("+string(smoothPeriod)+","+maName+")");
   IndicatorSetInteger(INDICATOR_DIGITS,1);

OnCalculateでは、次のように3つの整数変数を宣言します。

   int    i,pos,posCHV;

2-chvPeriodとsmoothPeriodの結果と同じになるようにposCHV変数を定義します。

   posCHV=chvPeriod+smoothPeriod-2;

rateTotalがposCHVの値より小さいかどうかを確認し、ゼロを返す必要があります。

   if(rates_total<posCHV)
      return(0);

prev_calculatedの値が1より小さいかどうかを確認した後、posの値を定義します。prev_calculatedの値が0か、条件がtrueでなければposはprev_calculatedの結果-1となります。

   if(prev_calculated<1)
      pos=0;
   else pos=prev_calculated-1;

hlBuffer[i]を定義します。

   for(i=pos;i<rates_total && !IsStopped();i++)
     {
      hlBuffer[i]=High[i]-Low[i];
     }

smoothedhl (shl)バッファを定義します。

   if(pos<smoothPeriod-1)
     {
      pos=smoothPeriod-1;
      for(i=0;i<pos;i++)
        {
         shlBuffer[i]=0.0;
        }
     }

関数SimpleMAOnBufferとExponentialMAOnBufferを使用して単純MAと指数MAを定義します。

   if(InpSmoothType==SMA)
     {
      SimpleMAOnBuffer(rates_total,prev_calculated,0,smoothPeriod,hlBuffer,shlBuffer);
     }
   else
      ExponentialMAOnBuffer(rates_total,prev_calculated,0,smoothPeriod,hlBuffer,shlBuffer);

posがposCHVより小さいかどうかを確認した後、posを更新します。

   if(pos<posCHV)
     {
      pos=posCHV;
     }

CHVバッファを定義します。

   for(i=pos;i<rates_total && !IsStopped();i++)
     {
      if(shlBuffer[i-chvPeriod]!=0.0)
         chvBuffer[i]=100.0*(shlBuffer[i]-shlBuffer[i-chvPeriod])/shlBuffer[i-chvPeriod];
      else
         chvBuffer[i]=0.0;
     }

rates_totalを返します。

return(rates_total);

以下は1ブロックのフルコードです。

//+------------------------------------------------------------------+
//|                                           Chaikin Volatility.mq5 |
//+------------------------------------------------------------------+
#include <MovingAverages.mqh>
#property description "Chaikin Volatility"
#property indicator_separate_window
#property indicator_buffers 3
#property indicator_plots   1
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  MediumBlue
#property indicator_width1  3
enum smoothMode
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          smoothPeriodInp=10;  // Smoothing Period
input int          chvPeriodInp=10;     // Chaikin Volatility Period
input smoothMode InpSmoothType=EMA;   // Smoothing Mode
double             chvBuffer[];
double             hlBuffer[];
double             shlBuffer[];
int                smoothPeriod,chvPeriod;
void OnInit()
  {
   string maName;
   if(InpSmoothType==SMA)
      maName="SMA";
   else
      maName="EMA";
   if(smoothPeriodInp<=0)
     {
      smoothPeriod=10;
      printf("Incorrect value for Smoothing Period input = %d. Default value = %d.",smoothPeriodInp,smoothPeriod);
     }
   else
      smoothPeriod=smoothPeriodInp;
   if(chvPeriodInp<=0)
     {
      chvPeriod=10;
      printf("Incorrect value for Chaikin Volatility Period input = %d. Default value = %d.",chvPeriodInp,chvPeriod);
     }
   else
      chvPeriod=chvPeriodInp;
   SetIndexBuffer(0,chvBuffer);
   SetIndexBuffer(1,hlBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,shlBuffer,INDICATOR_CALCULATIONS);
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,smoothPeriod+chvPeriod-1);
   PlotIndexSetString(0,PLOT_LABEL,"CHV("+string(smoothPeriod)+","+maName+")");
   IndicatorSetString(INDICATOR_SHORTNAME,"Chaikin Volatility("+string(smoothPeriod)+","+maName+")");
   IndicatorSetInteger(INDICATOR_DIGITS,1);
  }
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &Time[],
                const double &Open[],
                const double &High[],
                const double &Low[],
                const double &Close[],
                const long &TickVolume[],
                const long &Volume[],
                const int &Spread[])
  {
   int    i,pos,posCHV;
   posCHV=chvPeriod+smoothPeriod-2;
   if(rates_total<posCHV)
      return(0);
   if(prev_calculated<1)
      pos=0;
   else
      pos=prev_calculated-1;
   for(i=pos;i<rates_total && !IsStopped();i++)
     {
      hlBuffer[i]=High[i]-Low[i];
     }
   if(pos<smoothPeriod-1)
     {
      pos=smoothPeriod-1;
      for(i=0;i<pos;i++)
        {
         shlBuffer[i]=0.0;
        }
     }
   if(InpSmoothType==SMA)
     {
      SimpleMAOnBuffer(rates_total,prev_calculated,0,smoothPeriod,hlBuffer,shlBuffer);
     }
   else
      ExponentialMAOnBuffer(rates_total,prev_calculated,0,smoothPeriod,hlBuffer,shlBuffer);
   if(pos<posCHV)
     {
      pos=posCHV;
     }
   for(i=pos;i<rates_total && !IsStopped();i++)
     {
      if(shlBuffer[i-chvPeriod]!=0.0)
         chvBuffer[i]=100.0*(shlBuffer[i]-shlBuffer[i-chvPeriod])/shlBuffer[i-chvPeriod];
      else
         chvBuffer[i]=0.0;
     }
   return(rates_total);
  }

このコードをコンパイルした後で指標をチャートに貼り付ければ、次の図と同じ指標を見つけることができます。

CHVInda

前の図でわかるように、チャートの下部のウィンドウの指標はヒストグラムとして表示され、ゼロの上下に振動または記録されます。


チャイキンボラティリティ取引戦略

この部分では、チャイキンボラティリティ指標をどのように使 えば有利になるかを説明し、取引時にボラティリティを考慮するための取引シス テムの一部を紹介します。CHVのみを使用し、指標の値に基づいて売買を決定し、その結果が利益を生むかどうかをテストします。

このストラテジーの最適化として、移動平均の方向に基づいて判断する別の指標を組み合わせ、このストラテジーをテストした上で、CHVのみを使用するよりも利益が出るか、あるいは良くなるかどうかを確認します。

以下はその戦略です。

CHVクロスオーバー

このストラテジーは売買シグナルを生成し、自動的に注文を出すことができます。CHVの値がゼロを超えると、EAは買いポジションを建てます。CHVの値がゼロを下回ると、EAは売りポジションを建てます。

単純に言うと次のようになります。

CHV値 > 0 => 買いポジション

CHV値 < 0 => 売りポジション

CHVとMAのクロスオーバー

このストラテジーは、CHV値とゼロレベルとのクロスオーバーに基づき、移動平均の方向性を考慮したシグナルを生成し、売買ポジションを発注します。CHVがゼロを上回り、移動平均線が終値を下回れば、買いポジションが生成され、建てられます。一方、CHVがゼロを下回り、移動平均線が終値を上回る場合、売りポジションが生成され、建てられます。

単純に言うと次のようになります。

CHV > 0かつ終値 > MA => 買いポジション

CHV < 0かつ終値 < MA => 売りポジション


チャイキンボラティリティ取引システム

この部分では、前述のストラテジーに基づいてMQL5で取引システムを作成し、より良い結果を得るためにストラテジーをどのように最適化できるかを確認するために、それぞれのストラテジーをテストします。まず、2つのストラテジーの取引システムの元となるシンプルなEAを作成し、このEAはCHV値をチャートにコメントとして表示します。次が手順です。

指標に基づく取引システムの入力を宣言します。

enum SmoothMethod
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          InpSmoothPeriod=10;  // Smoothing period
input int          InpCHVPeriod=10;     // Chaikin Volatility period
input SmoothMethod InpSmoothType=EMA;   // Smoothing method

chv用の整数変数を宣言します。

int chv;

EAのOnInit()で、CHV指標のハンドルを返す iCustom関数と等しくなるようにchv変数を定義します。iCustomのパラメータは以下の通りです。

  • symbol_name:銘柄(現在の銘柄に適用される_Symbolを使用)
  • period:期間(現在の期間に適用されるPERIOD_CURRENTを使用)
  • name:指標の名前
  • 入力リストの指定(smoothPeriodInp, chvPeriodInp, smoothTypeInp)
chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",smoothPeriodInp,chvPeriodInp, smoothTypeInp);

OnDeinit()で、EAが削除されたときのメッセージを表示します。

Print("EA is removed");

OnTick()で、chvInd配列を宣言します。

double chvInd[];

CopyBufferキーワードを使用して、CHV指標の指定されたバッファデータを取得します。パラメータは次の通りです。

  • indicator_handle:指標のハンドル(chvを使用) 
  • buffer_num:指標バッファ番号(0を使用)
  • start_pos:開始位置(0を使用)
  • count:コピーする量(3を使用)
  • buffer[]:コピー先の配列(chvInd)
CopyBuffer(chv,0,0,3,chvInd);

ArraySetAsSeriesとそのパラメータを使用して、選択された配列にAS_SERIESフラグを設定します。

  • array[]:配列を参照で指定(chvInd) 
  • フラグ:インデックスの順序が逆であることを示すtrueを設定 
ArraySetAsSeries(chvInd,true);

指標の現在値を返すchvValを宣言し、定義します。

double chvVal = NormalizeDouble(chvInd[0], 1);

チャート上の現在値をコメントします。

Comment("CHV value = ",chvVal);

完全なコードは次のように1つのブロックで見ることができます。

//+------------------------------------------------------------------+
//|                                                       chvVal.mq5 |
//+------------------------------------------------------------------+
enum SmoothMethod
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          smoothPeriodInp=10;  // Smoothing period
input int          chvPeriodInp=10;     // Chaikin Volatility period
input SmoothMethod smoothTypeInp=EMA;   // Smoothing method
int chv;
int OnInit()
  {
   chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",smoothPeriodInp,chvPeriodInp, smoothTypeInp);
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("EA is removed");
  }
void OnTick()
  {
    double chvInd[];
    CopyBuffer(chv,0,0,3,chvInd);
    ArraySetAsSeries(chvInd,true);
    double chvVal = NormalizeDouble(chvInd[0], 1);
    Comment("CHV value = ",chvVal);
  }
//+------------------------------------------------------------------+

このコードをコンパイルすると、以下の図のように現在値が表示されます。

chvVal

チャートに表示された値が正しいかどうかをみるには、同じチャートに指標を挿入し、2つの値に差があるかどうかを確認できます。そこで、取引システムの作成に進む前に、すべてが正しいことを確認するために、次のチャートを示します。

chvValSame

見てわかるように、現在のCHVの出力値は、付属の指標の値と同じです。では、最初のストラテジー(CHVクロスオーバー)の取引システムを作成してみましょう。

CHVクロスオーバー

以下はCHVクロスオーバー戦略の完全なコードです。

//+------------------------------------------------------------------+
//|                                                 chvCrossover.mq5 |
//+------------------------------------------------------------------+
#include <trade/trade.mqh>
enum smoothMode
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          smoothPeriodInp=10;  // Smoothing period
input int          chvPeriodInp=10;     // Chaikin Volatility period
input smoothMode smoothTypeInp=EMA;   // Smoothing Mode
input double      lotSize=1;
input double slPips = 300;
input double tpPips = 600;

int chv;
int barsTotal;
CTrade trade;
int OnInit()
  {
   barsTotal=iBars(_Symbol,PERIOD_CURRENT);
   chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",smoothPeriodInp,chvPeriodInp, smoothTypeInp, lotSize, slPips, tpPips);
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("EA is removed");
  }
void OnTick()
  {
   int bars=iBars(_Symbol,PERIOD_CURRENT);
   if(barsTotal < bars)
     {
      barsTotal=bars;
      double chvInd[];
      CopyBuffer(chv,0,0,3,chvInd);
      ArraySetAsSeries(chvInd,true);
      double chvVal = NormalizeDouble(chvInd[0], 1);
      double chvValPrev = NormalizeDouble(chvInd[1], 1);
      if(chvVal>0)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal = ask - slPips*_Point;
         double tpVal = ask + tpPips*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }
      if(chvVal<0)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal = bid + slPips*_Point;
         double tpVal = bid - tpPips*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }
     }
  }
//+------------------------------------------------------------------+

このコードの違いは以下の通りです。

取引機能の取引ファイルをインクルードします。

#include <trade/trade.mqh>

lotSize、slPips、tpPipsの入力をユーザーが編集できるように宣言します。

input double      lotSize=1;
input double slPips = 300;
input double tpPips = 600;

各新しいバーのコードとして使用されるbarsTotalの整数変数を宣言します。

int barsTotal;

取引目的を宣言します。

CTrade trade;

OnInit()で、変数barsTotalを定義します。

barsTotal=iBars(_Symbol,PERIOD_CURRENT);

iCustomにlotSize、slPips、tpPipsの3つの入力を追加します。

chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",smoothPeriodInp,chvPeriodInp, smoothTypeInp, lotSize, slPips, tpPips);

整数変数barsを宣言・定義します。

int bars=iBars(_Symbol,PERIOD_CURRENT);

barsTotalがbarsより小さいかどうかを確認するために、以下を実行する必要があります。

barsTotalの値がbarsの値と等しくなるように更新します。

barsTotal=bars;

chvInd配列を宣言します。

double chvInd[];

CopyBufferによってCHV指標の指定されたバッファデータを取得します。

CopyBuffer(chv,0,0,3,chvInd);

以下のように、ArraySetAsSeriesを使用して、選択された配列にAS_SERIESフラグを設定します。

ArraySetAsSeries(chvInd,true);

指標の現在値と現在値の前回値を返すためのchvValを宣言・定義します。

      double chvVal = NormalizeDouble(chvInd[0], 1);
      double chvValPrev = NormalizeDouble(chvInd[1], 1);

買いポジションの条件を設定するには、EAがCHV値を確認し、それがゼロより大きいと判断したときに、自動的に買いポジションを建てる必要があります。

      if(chvVal>0)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal = ask - slPips*_Point;
         double tpVal = ask + tpPips*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }

売りポジションの条件を設定するには、EAがCHV値を確認し、それがゼロより小さいと判断したときに、自動的に売りポジションを置く必要があります。

      if(chvVal<0)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal = bid + slPips*_Point;
         double tpVal = bid - tpPips*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }

このコードをコンパイルすると、買いポジションは次のようになることがわかります。

chvCrossover_buySignal

売りポジションは次のようになることがわかります。

chvCrossover_sellSignal

ご存じのように、テストして有益な結果を得なければ、良い戦略は存在しません。以下の主要な測定に焦点を当てます。

  • 純利益:売上総利益から売上総損失を差し引くことで算出。高いほど良い
  • バランスDD(相対):取引中に口座が経験する最大損失額。低いほど良い
  • プロフィットファクター:売上総利益と売上総損失の比率。高いほど良い
  • 期待損益:これは取引の平均損益。高いほど良い
  • リカバリーファクター:テストされたストラテジーが損失後にどの程度回復するかを測定するもの。高いほど良い
  • シャープレシオ:リスクフリーリターンとリターンを比較することで、テストされた取引システムのリスクと安定性を判断します。高いほど良い

というわけで、以下のグラフはテスト結果です。EURUSDと1時間の時間枠で1年間(1-1-2023から31-12-2023まで)テストします。

chvCrossover_result

chvCrossover_result2

chvCrossover_result1

テスト結果によると、テストからの重要な値は以下の通りです。

  • 純利益:-35936.34米ドル
  • 相対的なバランスDD:48.12%
  • プロフィットファクター:0.94
  • ペイオフ期待値:-6.03
  • リカバリーファクター:-0.62
  • シャープレシオ:-1.22。

これまでの結果を見ると、結果が良くなかったり、利益が出なかったりすることがわかります。したがって、改善してより良い結果を得るためには、それらを最適化する必要があります。以下では、戦略を通じてそれを実行します。

CHVとMAのクロスオーバー

この戦略では、CHV指標を使用しますが、もう1つのテクニカル指標であ る移動平均を組み合わせ、移動平均の方向に基づいて取引をフィルタリングします。以下はそのための完全なコードです。

//+------------------------------------------------------------------+
//|                                             chv_MA_Crossover.mq5 |
//+------------------------------------------------------------------+
#include <trade/trade.mqh>
enum smoothMode
  {
   SMA=0,// Simple MA
   EMA=1 // Exponential MA
  };
input int          InpSmoothPeriod=10;  // Smoothing period
input int          InpCHVPeriod=10;     // Chaikin Volatility period
input smoothMode smoothTypeInp=EMA;   // Smoothing Mode
input int InpMAPeriod=10; //MA Period
input ENUM_MA_METHOD InpMAMode=MODE_EMA; // MA Mode
input double      lotSize=1;
input double slPips = 300;
input double tpPips = 600;
int chv;
int ma;
int barsTotal;
CTrade trade;
int OnInit()
  {
   barsTotal=iBars(_Symbol,PERIOD_CURRENT);
   chv = iCustom(_Symbol,PERIOD_CURRENT,"Custom_CHV",InpSmoothPeriod,InpCHVPeriod, smoothTypeInp, lotSize, slPips, tpPips);
   ma=iMA(_Symbol,PERIOD_CURRENT, InpMAPeriod, 0, InpMAMode, PRICE_CLOSE);
   return(INIT_SUCCEEDED);
  }
void OnDeinit(const int reason)
  {
   Print("EA is removed");
  }
void OnTick()
  {
   int bars=iBars(_Symbol,PERIOD_CURRENT);
   if(barsTotal < bars)
     {
      barsTotal=bars;
      double chvInd[];
      double maInd[];
      CopyBuffer(chv,0,0,3,chvInd);
      ArraySetAsSeries(chvInd,true);
      CopyBuffer(ma,0,0,3,maInd);
      ArraySetAsSeries(maInd,true);
      double chvVal = NormalizeDouble(chvInd[0], 1);
      double chvValPrev = NormalizeDouble(chvInd[1], 1);
      double maVal = NormalizeDouble(maInd[0], 5);
      double maValPrev = NormalizeDouble(maInd[1], 5);
      double lastClose=iClose(_Symbol,PERIOD_CURRENT,1);
      double prevLastClose=iClose(_Symbol,PERIOD_CURRENT,2);

      if(prevLastClose<maValPrev && lastClose>maVal && chvVal>0)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal = ask - slPips*_Point;
         double tpVal = ask + tpPips*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }
      if(prevLastClose>maValPrev && lastClose<maVal && chvVal<0)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal = bid + slPips*_Point;
         double tpVal = bid - tpPips*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }
     }
  }
//+------------------------------------------------------------------+

このコードの違いは以下の通りです。

整数変数maを宣言します。

int ma;

OnInit()で、iMAを使用してmaを定義し、移動平均のハンドルを返します。パラメータは次の通りです。

  • symbol:銘柄(現在の銘柄に適用される_Symbolを使用) 
  • period:時間枠(現在の時間枠に適用されるPERIOD_CURRENTを使用)
  • ma_period:移動平均の期間(MAperiodのユーザー入力を使用)
  • ma_shift:平均線に水平方向のシフトが必要かどうかを指定
  • ma_method:移動平均の平滑化モード 
  • applied_pric計算に使用する価格の種類(終値を使用)
ma=iMA(_Symbol,PERIOD_CURRENT, InpMAPeriod, 0, InpMAMode, PRICE_CLOSE);

新しいバーがあるかどうかを確認した後、以下を追加します。

maInd[]配列を宣言します。

double maInd[];

CopyBufferキーワードを使用して移動平均指標の指定されたバッファのデータを取得し、 ArraySetAsSeriesを使用して、選択された配列に AS_SERIESフラグを設定します。

      CopyBuffer(ma,0,0,3,maInd);
      ArraySetAsSeries(maInd,true);

次の値を定義します。

現在の移動平均線、以前の移動平均線、直前の終値、以前の直前の終値

      double maVal = NormalizeDouble(maInd[0], 5);
      double maValPrev = NormalizeDouble(maInd[1], 5);
      double lastClose=iClose(_Symbol,PERIOD_CURRENT,1);
      double prevLastClose=iClose(_Symbol,PERIOD_CURRENT,2);

買いポジションの条件を設定します。前回の終値が前回の移動平均値より小さく、同時に前回の終値が現在の移動平均値より大きく、同時に現在のチャイキン値が0より大きい場合、EAに買いポジションを建てさせます

      if(prevLastClose<maValPrev && lastClose>maVal && chvVal>0)
        {
         double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
         double slVal = ask - slPips*_Point;
         double tpVal = ask + tpPips*_Point;
         trade.Buy(lotSize,_Symbol,ask,slVal,tpVal);
        }

売りポジションの条件を設定します。前回の終値が前回の移動平均値より大きく、同時に前回の終値が現在の移動平均値より小さく、同時に現在のチャイキン値がゼロより小さい場合、EAに売りポジションを建てさせます

      if(prevLastClose>maValPrev && lastClose<maVal && chvVal<0)
        {
         double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
         double slVal = bid + slPips*_Point;
         double tpVal = bid - tpPips*_Point;
         trade.Sell(lotSize,_Symbol,bid,slVal,tpVal);
        }

このコードをコンパイルすると、買いポジションは次のようになることがわかります。

chvMACrossover_buySignal

売りポジションは次のようになることがわかります。

chvMACrossover_sellSignal

このストラテジーを1年間(2023年1月1日から2023年12月31日まで)EURUSDと1時間足でテストした結果は以下の通りです。

chvMACrossover_result

chvMACrossover_result2

chvMACrossover_result1

テスト結果によると、テストからの重要な値は以下の通りです。

  • 純利益:20817.39米ドル
  • 相対的なバランスDD:9.62%
  • プロフィットファクター:1.15
  • 期待損益:29.28
  • リカバリーファクター:1.69
  • シャープレシオ:1.71

前のテストの結果に基づいて、別の技術的なツールとして移動平均を追加した後、1時間足でのCHVとMAクロスオーバーのテスト戦略に対応する最高の数字は次のようになります。

  • 純利益: 最高20817.39米ドル
  • バランスDD(相対):最低9.62%
  • プロフィットファクター:最高1.15
  • 期待損益:最高29.28
  • リカバリーファクター:最高1.69
  • シャープレシオ:最高1.71


結論

チャイキンボラティリティというテクニカル指標を学ぶことで、金融市場におけるボラティリティの概念の重要性を理解しました。これは、潜在的な市場の動きを読み取ったり予測したりするのに役立ちます。CHV指標がどのように機能し、どのように計算され、どのように取引市場で有利に利用できるかを理解しました。

2つの単純な戦略を理解し、移動平均線などの別のテクニカルツールを併用することで、より良い結果を得るために戦略を最適化する方法を理解しました。MQL5を使用して独自のCHV指標を作成し、それに好みを追加できるようにする方法を学び、このカスタムCHV指標を前述のストラテジーに基づく取引システムで使用する方法を学びました。

  • CHVクロスオーバー
  • CHVとMAのクロスオーバー

また、EAを作成し、それをテストし、ストラテジーテスターを通じて移動平均線のような別のテクニカルツールを最適化として併用することで、より良い洞察と結果を得ることができるかを確認することで、前述のストラテジーに基づいて自動的に機能し、ポジションを建てる取引システムを作成する方法を学びました。

より良い洞察力を得るために、他の可能性のあるツールを試してみることをお勧めします。取引システムの構築やその背後にある主要な概念の理解に関する記事をもっと読みたい方は、これらのトピックやMQL5プログラミングに関連する他のトピックに関する私の過去の記事をお読みください。


MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/14775

添付されたファイル |
Custom_CHV.mq5 (3.24 KB)
chvVal.mq5 (0.97 KB)
chvCrossover.mq5 (1.8 KB)
GMDH (The Group Method of Data Handling):MQL5で組合せアルゴリズムを実装する GMDH (The Group Method of Data Handling):MQL5で組合せアルゴリズムを実装する
この記事では、MQL5における組合せアルゴリズムと、その改良版である組合せ選択(Combinatorial Selective)アルゴリズムの実装について、データ処理のグループ法アルゴリズムファミリーの探求を続けます。
Candlestick Trend Constraintモデルの構築(第1回):EAとテクニカル指標について Candlestick Trend Constraintモデルの構築(第1回):EAとテクニカル指標について
この記事は初心者とプロMQL5開発者の両方を対象としています。これは、シグナルを生成する指標をより長い時間枠のトレンドに定義し、制約するためのコードの一部を提供します。このように、トレーダーはより広い市場視点を取り入れることで戦略を強化することができ、より強固で信頼性の高い売買シグナルが得られる可能性があります。
知っておくべきMQL5ウィザードのテクニック(第17回):多通貨取引 知っておくべきMQL5ウィザードのテクニック(第17回):多通貨取引
ウィザードを介してEAが組み立てられた場合、デフォルトでは複数の通貨をまたいだ取引は利用できません。トレーダーが一度に複数の銘柄から自分のアイデアをテストする際に、2つの可能なトリックを検討します。
知っておくべきMQL5ウィザードのテクニック(第16回):固有ベクトルによる主成分分析 知っておくべきMQL5ウィザードのテクニック(第16回):固有ベクトルによる主成分分析
データ分析における次元削減技術である主成分分析について、固有値とベクトルを用いてどのように実装できるかを考察します。いつものように、MQL5ウィザードで使用可能なExpertSignalクラスのプロトタイプの開発を目指します。