2016年1月15日金曜日

[MT4インジケータ]TickEMA EMAの反応を取引の活発さによって変動する。


・図1 EMA(21)赤 と TickEMA(緑)

MQL超入門でTick更新回数をサブチャートに出すと何か見えないか?ということで作ってみましたが、応用してみたいと思います。

MQL超入門のTick更新回数インジケータを作成するシリーズ
http://mt4program.blogspot.com/2016/01/mql-009.html
http://mt4program.blogspot.com/2016/01/mql-010-tick.html
http://mt4program.blogspot.jp/2016/01/mql-011.html
http://mt4program.blogspot.com/2016/01/mql-012.html

移動平均の計算において、ある特定時間ごとの値から算出します。
たとえば、EMAですと次の式です。

EMA[i]=Price * α + (1-α) * EMA[i-1]

ここでのPriceはEMA算出元となる価格です。たとえばクローズ値です。

EMAはとても優秀だと思いますが、たとえばTickの更新回数が1000回の時間と100回の時間では重みが違うのではないでしょうか?上記計算式ではその部分は考慮されていないため全く同じ影響力があります。
そこで、MQL超入門で作成したTickVolumeインジケータのコードを利用して、TickVolumeを考慮して重みが変化するEMAを作ってみました。計算式は下記の通りです。

α=基準α*Tick更新回数/Tick更新回数の平均値
EMA[i]=Price * α + (1-α) * EMA[i-1]

※ただしαは0~1までの間とする。

これを適用したのが図1のチャートです。赤がMT4に標準でついているEMA(21)、緑がTickEMA(21)です。
図1では綺麗に出た場合の例ですが、活発さを伴って上昇していく場合は緑のラインが赤を追い越します。活発さが無い場合は、逆に赤のラインが追い越します。

ただし活発さを伴わずだらだらと一方方向に移動するときもあるため、信頼性に欠けるというだけでクロスしたから取引のシグナルとは限らないように思われます。
ちなみにインジケータに[加速方向のみの場合True]というパラメータがありますが、これをTrueにすると活発さを伴って価格が移動した場合にのみα値が変化するようになります。この場合次のようになります。

・図2 EMA(21)赤 と TickEMA(緑) 加速方向のみTrue時


さて、シグナルに使えるかを検証するためバックテストで試してみましょう。バックデータはAlpariです。

EURUSD1Hベースにて最大48時間ポジション保持、EMA(21)とTickEMA(21)のラインクロスで単純売買の結果です。損切・利確なしです。確定足でのラインクロス時に反対方向のポジションは全決済しています。

まずは、加速方向のみはTrueを設定して確認してみましょう。

・図3 EURUSD1H 2011-2015 加速方向のみTrue

まぁマイナスに沈みますね。ただ、PF0.98と移動平均のラインクロス売買にしてはかなりの好成績とも言えます。

ちなみに、加速方向のみをFalseにした場合はこちら

・図4 EURUSD1H 2011-2015 加速方向のみFalse

一昨年までは、ほぼ横ばい、去年は大きくマイナスといった感じです。
こちらはPF0.97で同じくラインクロスとしてはかなりの好成績のように思えます。

お互い少し工夫をするといろいろできそうな雰囲気です。例えば、図3のEAに4時間足でのEMAとTickEMAの位置も判断材料として加えてみましょう。

・図5 図3のEAに4時間足も見るように変更
プラスになりました。
やはり、少し工夫すると使えそうな予感がします。

EAのフィルタとして取引時間(例えば深夜帯はボラが低いから取引しない)等のフィルタを使用するより、活発さというデータがせっかくMT4で公開されていますので、是非有効活用していきたいです。

あ、蛇足ですが、本記事がMT4開発日記記念の200記事目になりました。皆様ご愛読ありがとうございます^^
・・・・・とはいっても、現在は100PV/1Dを割ってまして初心者ブロガーの域を全く超えていません。内容がマニアックすぎるのかなぁ?^^;;;

プロぐランキングにご協力よろしくお願いします。m(._.)m
にほんブログ村 為替ブログへ

ソースコードはこちらから




//------------------------------------------------------------------
// Tick更新回数をみて変更するEMA/SmoothMA
#property copyright "Copyright 2016,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict
#property indicator_chart_window

//バッファーを指定する。
#property indicator_buffers 1

//プロット数を指定する。
#property indicator_plots   1

#property indicator_label1  "MA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrYellow
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

input int SmoothPeriod = 4;   // ボリューム値平滑化期間
input int AveragePeriod = 100; // 平均期間

input int MaPeriod = 21;// 移動平均期間
input int   MaShift = 0;// 表示移動
input ENUM_APPLIED_PRICE MaPrice = PRICE_CLOSE;//適用価格

input bool IsAcceralationOnly = false;//加速方向のみの場合True

// 表示バッファ
double ma[];

// 平滑化指数
double alfa;

//------------------------------------------------------------------
//初期化
int OnInit()
{
   SetIndexBuffer(0,ma);
   
   alfa = 2.0 / ( MaPeriod + 1.0); 
   
   SetIndexShift(0, MaShift);

   return INIT_SUCCEEDED;
}

//------------------------------------------------------------------
//計算イベント
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 &tick_volume[],      //ティック数(要素の更新回数)
                const long &volume[],           //実ボリューム(?)
                const int &spread[])            //スプレット
{
   for( int i = rates_total - prev_calculated - 1; i >= 0; i-- )
   {
      // Tick値の線形加重移動平均を求める。
      double smoothVolume = 0 ;
      int count = 0 ;
      for( int j = 0; j < SmoothPeriod && (i + j) < rates_total; j++ )
      {
         int weight = SmoothPeriod - j;
         count += weight;
         smoothVolume += (double)tick_volume[i + j] * weight;
      }
      if( count > 0 )
      {
         smoothVolume = smoothVolume / count;
      }

      // Tick値の単純平均を求める。
      double average = 0 ;
      count = 0 ;

      for( int j = 0; j < AveragePeriod && (i + j) < rates_total; j++ )
      {
         count++;
         average += (double)tick_volume[i + j];
      }
      if( count > 0 )
      {
         average = average / count;
      }
      
      //EMAを計算する。
      double price = GetPrice(open[i], close[i], high[i], low[i], MaPrice);
      if( average > 0 && (i + 1) < rates_total)
      {
         double currentAlfa = alfa * smoothVolume / average;
//         double currentAlfa = smoothVolume > average ? (alfa * 2) : (alfa / 2);

         if( currentAlfa >= 1 ) currentAlfa = 1;
         if( IsAcceralationOnly && currentAlfa < alfa ) currentAlfa = alfa;
   
         // 指数平滑化移動平均
         ma[i] = price * currentAlfa + (1 - currentAlfa) * ma[i + 1]; 
      }
      else
      {
         ma[i] = price;
      }
   }
   
   return rates_total - 1;
}

//------------------------------------------------------------------
// 価格を計算する。
// return 対象価格
double GetPrice(
   double open,   // オープン値
   double close,  // クローズ値
   double high,   // 高値
   double low,    // 安値
   ENUM_APPLIED_PRICE maPrice    //取得価格
   )
{
   double price = 0;

   switch( maPrice )
   {
      case PRICE_CLOSE:
         price = close;
         break;
      case PRICE_OPEN:
         price = open;
         break;
      case PRICE_HIGH:
         price = high;
         break;
      case PRICE_LOW:
         price = low;
         break;
      case PRICE_MEDIAN:
         price = (high + low) / 2;
         break;
      case PRICE_TYPICAL:
         price = (high + low + close) / 3;
         break;
      case PRICE_WEIGHTED:
         price = (high + low + close + close) / 4;
         break;
   }
   return price;
}