2016年3月22日火曜日

[MT4インジケータ]Tick値でプロファイルを作ってみる。マーケットプロファイル その2

ということで、第2弾としてTick値をカウントしてプロファイルを作ってみたいと思います。

前回TickVolumeを作りましたが、あちらは時間軸でのTick値を表示していました。
Tick値で重みが変わるEMAとTick値のインジケータ
Tick値で重みが変わるEMAとTick値のインジケータ
Tick値で重みが変わるEMAとTick値のインジケータ | fx-on.com

対してこちらは価格軸でまとめてみた物です。

■EURUSD 3/4 マーケットプロファイル(上)とTickプロファイル(下)

プロファイルが日本時間に大きな山ができているのに対して、TickプロファイルはEU時間に厚みのある山ができていることがわかります。よりはっきりと二つの山が形成されていることがわかるようになった気がします。次の日も見てみましょう。

■EURUSD 3/5 マーケットプロファイル(上)とTickプロファイル(下)


こちらは日本時間で発生した山とEU時間で発生した山の大きさが逆転しています。EU時間のほうが影響力が高い山ということがわかります。

■EURUSD 3/10 マーケットプロファイル(上)とTickプロファイル(下)

最後はECB理事会での値動きをプロファイルで見てみたいと思います。
ECB理事会が始まるまで狭い範囲で戦いを繰り広げていた様子が、プロファイル、Tickプロファイル両方から見て取れます。

そのあと、いったん100pips下がって300pips上がる動きとなります。プロファイルでは大きく動いた時間にほとんど山は発生していませんが、Tick値では、ECB理事会の後、下に下がった後、急激にTick値が伸び、その後反発いったんの上げで利食いが発生した後、再上昇なかでTick値を伴いながらも上昇していく様子がわかります。プロファイルを見ていると、上昇時厚みのあるプロファイルを描くと、いったんの天井になることが多いように見えますが、はっきりとは調査できていません。

プロファイルの形が回数カウントよりはっきり出る気がするので、形状を研究すると何か見えてくる予感がしてきます。現状EAにはちょっと使いにくいですね。

試してみるとすると、前日のTickプロフィットの山の頂点位置から下にいる場合は売り、上にいる場合は買いとかでしょうか?

FX-ONからの無料ダウンロードはこちらから
Tick回数を価格軸で並べる
TickProfile
TickProfile | fx-on.com

■マーケットTickプロファイルシリーズ
・2/3と3/18のプロファイル形状が似ている。Tickプロファイル覚書
http://mt4program.blogspot.jp/2016/03/mt423318tick.html

・マーケットプロファイルを眺めてみる。マーケットプロファイル その1
http://mt4program.blogspot.jp/2016/03/mt4_21.html

・Tick値でプロファイルを作ってみる。マーケットプロファイル その2
http://mt4program.blogspot.jp/2016/03/mt4tick.html

・マーケットプロファイルを色分けして表示する。マーケットプロファイル その3
http://mt4program.blogspot.jp/2016/03/mt4_24.html

MT4開発日記で公開している無料インジケータは、こちらの一覧から。
インジケータ一覧

Twitterもよろしくお願いします。
https://twitter.com/mt4program

ブログランキングにご協力よろしくお願いします。m(._.)m
にほんブログ村 為替ブログ FX システムトレード派へ
にほんブログ村

お約束ですが、本ブログは、投資に対する利益を約束する物ではありません。最終的には自己責任によるご判断よろしくお願いいたします。

プログラムはこちらから

//------------------------------------------------------------------
// マーケットTickプロファイル
#property copyright "Copyright 2016,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict
#property indicator_chart_window

input int StartHour = 0; //開始時間

input color RectangleColor = clrSkyBlue;  // 矩形枠線色
input color ProfileColor = clrDarkGray;   // プロファイルの色

input int DrawProfileCount = 10;       //最初に描画するプロファイル数
input int ProfileResolutionPips = 5;   // プロファイルの解像度(PIPS)

input bool AutoWidth = true;           // 横幅を最大値が矩形の2/3になるよう自動調整する。
input int ProfitWidth = 1000;  // AutoWidth=false時のプロフィットベースの矩形横幅

input bool IsTickCount = true;      // Tick値を数える場合true

input ENUM_TIMEFRAMES CountPeriod = PERIOD_M1;  // カウントする時間足

#define OBJECT_NAME "MKTKPF"

//------------------------------------------------------------------
//初期化
int OnInit()
{
   string short_name = "MTP";
   IndicatorShortName(short_name);
   return(INIT_SUCCEEDED);
}

//------------------------------------------------------------------
//終了処理
void OnDeinit(const int reason)
{
   long chartId = ChartID();

   int total = ObjectsTotal(chartId);
   //生成したオブジェクトを削除する。
   //0から削除するとインデックス位置がずれて
   //正しく削除できないため、後ろから削除するようにする。
   for( int i = total - 1; i >= 0 ; i--)
   {
      string name = ObjectName(chartId, i);
      
      // 先頭文字列がOBJECT_NAMEと一致する場合、削除する。
      if( StringFind(name, OBJECT_NAME) == 0 )
      {
         ObjectDelete(chartId, name);
      }
   }
}


//------------------------------------------------------------------
//計算イベント
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[])            //スプレット
{
   // オフラインチャートじゃ動かないかも・・・。
   if( Period() > PERIOD_H4 ) return rates_total;
   
      //Pips計算 小数点桁数が3or5の場合、Point()*10=1pips
   int digit = (int)MarketInfo(Symbol(), MODE_DIGITS);
   double point = (double)MarketInfo(Symbol(), MODE_POINT);
   double onePips = point * (digit == 3 || digit == 5 ? 10 : 1);
   
   int drawCount = 0 ;
   for( int i = 0; i < rates_total && !IsStopped(); i++ )
   {
      MqlDateTime current;
      TimeToStruct(time[i], current);
      
      if( current.hour == StartHour )
      {
         current.sec = 0;
         current.min = 0;

         datetime baseTime = StructToTime(current);
         i = iBarShift(Symbol(), Period(), baseTime);
         if( i < 0 ) break ;
      
         // 矩形を描画する。
         datetime endTime = baseTime + 24 * 60 * 60 - 1;
         int barShift = iBarShift(Symbol(), Period(), endTime);
         if( barShift < 0 ) barShift = 0;
         
         int highest = iHighest(Symbol(), Period(), MODE_HIGH, i - barShift + 1, barShift);
         double rangeHigh = iHigh( Symbol(), Period(), highest);
         int lowest = iLowest(Symbol(), Period(), MODE_LOW, i - barShift + 1, barShift);
         double rangeLow = iLow( Symbol(), Period(), lowest);
      
         CreateRectangleObject(baseTime, endTime, rangeHigh, rangeLow, RectangleColor);
         
         // プロファイルの描画        
         double resolution = ProfileResolutionPips * onePips;
         double center = (rangeHigh + rangeLow) / 2;

         int startShift = iBarShift(Symbol(), CountPeriod, baseTime);
         int endShift = iBarShift(Symbol(), CountPeriod, endTime);
         
         // 開始シフトが取れない場合は、プロファイル作成不能
         if( startShift < 0 ) break ;
         if( endShift < 0 ) endShift = 0;
         
         if( startShift != endShift )
         {
            // プロファイル数のカウント
            int resolutionCount = (int)( (rangeHigh - center) * 2 / resolution + 2);
            double profile[];
            ArrayResize(profile, resolutionCount);
            ArrayInitialize(profile, 0);

            for( int j = startShift; j >= endShift; j-- )
            {
               double profileClose = iClose(Symbol(), CountPeriod, j);
               
               int index = (int)MathFloor( (profileClose - rangeLow) / resolution); 
               if(index >= resolutionCount) index = resolutionCount - 1;
               
               if( IsTickCount )
               {
                  profile[index] += (int)iVolume(Symbol(), CountPeriod, j);
               }
               else
               {
                  profile[index] ++;
               }
            }
            
            DeleteProfileRectangleObject(baseTime);
            
            //矩形に対して2/3位置まで描画する。
            int maxCount = (int)ProfitWidth;
            if( AutoWidth )
            {
               maxCount = (int)(profile[ArrayMaximum(profile)] * 3 / 2);
            }
            
            for( int j = 0; j < resolutionCount; j++ )
            {
               double bottom = center - resolution * resolutionCount / 2 + j * resolution; 
               double top = bottom + resolution; 
               
               datetime rightTime = baseTime + (int) (profile[j] * 86400 / maxCount);
               
               CreateProfileRectangleObject(j, baseTime, rightTime, top, bottom, ProfileColor);
            }
         } 
        
         drawCount++;
      }
      
      if( (drawCount > 0 && i >= rates_total - prev_calculated) || drawCount >= DrawProfileCount ) break ;
   }
   //元となる値を計算する。
   return(rates_total - 1);
}

//------------------------------------------------------------------
//プロファイル矩形を削除する
// 成功時 True
bool DeleteProfileRectangleObject
   ( datetime startTime    // 開始時間
   )
{
   //オブジェクトを作成する。
   long chartId = ChartID();

   string pfName = OBJECT_NAME  + "_PF_" + TimeToStr(startTime);

   int total = ObjectsTotal(chartId);
   //生成したオブジェクトを削除する。
   //0から削除するとインデックス位置がずれて
   //正しく削除できないため、後ろから削除するようにする。
   for( int i = total - 1; i >= 0 ; i--)
   {
      string name = ObjectName(chartId, i);
      
      // 先頭文字列がOBJECT_NAMEと一致する場合、削除する。
      if( StringFind(name, pfName) == 0 )
      {
         ObjectDelete(chartId, name);
      }
   }
   
   return true;
}

//------------------------------------------------------------------
//プロファイル矩形を生成する。
// 生成成功時 True
bool CreateProfileRectangleObject
   ( int i                 // インデックス
   , datetime startTime    // 開始時間
   , datetime endTime      // 終了時間
   , double top            // 上限価格
   , double bottom         // 下限価格
   , color backColor       // 背景色
   )
{
   //オブジェクトを作成する。
   long chartId = ChartID();

   string name = OBJECT_NAME  + "_PF_" + TimeToStr(startTime) + "_" + IntegerToString(i);

   int index = ObjectFind( chartId, name );
   if( index < 0 )
   {
      if ( ObjectCreate( chartId, name, OBJ_RECTANGLE, 0, startTime, top, endTime, bottom ) == false )
      {
         return false;
      }
      ObjectSetInteger( chartId, name, OBJPROP_COLOR, backColor );
      ObjectSetInteger(chartId, name, OBJPROP_HIDDEN, true);
      ObjectSetInteger(chartId, name, OBJPROP_SELECTABLE, false);
   }
   else
   {
      ObjectSetInteger( chartId, name, OBJPROP_TIME1, startTime);
      ObjectSetInteger( chartId, name, OBJPROP_TIME2, endTime);
      ObjectSetDouble( chartId, name, OBJPROP_PRICE1, top);
      ObjectSetDouble( chartId, name, OBJPROP_PRICE2, bottom);
   }

   return true;
}

//------------------------------------------------------------------
//矩形を生成する。
// 生成成功時 True
bool CreateRectangleObject
   ( datetime startTime    // 開始時間
   , datetime endTime      // 終了時間
   , double top            // 上限価格
   , double bottom         // 下限価格
   , color backColor       // 背景色
   )
{
   //オブジェクトを作成する。
   long chartId = ChartID();

   string name = OBJECT_NAME + TimeToStr(startTime);

   int index = ObjectFind( chartId, name );
   if( index < 0 )
   {
      if ( ObjectCreate( chartId, name, OBJ_RECTANGLE, 0, startTime, top, endTime, bottom ) == false )
      {
         return false;
      }
      ObjectSetInteger( chartId, name, OBJPROP_BACK, false );
      ObjectSetInteger( chartId, name, OBJPROP_COLOR, backColor );
      ObjectSetInteger(chartId, name, OBJPROP_HIDDEN, true);
      ObjectSetInteger(chartId, name, OBJPROP_SELECTABLE, false);
   }
   else
   {
      ObjectSetInteger( chartId, name, OBJPROP_TIME1, startTime);
      ObjectSetInteger( chartId, name, OBJPROP_TIME2, endTime);
      ObjectSetDouble( chartId, name, OBJPROP_PRICE1, top);
      ObjectSetDouble( chartId, name, OBJPROP_PRICE2, bottom);
   }

   return true;
}

//------------------------------------------------------------------
//矩形オブジェクトを削除する
bool DeleteRectangleObject(
   datetime time           //表示時間(横軸)
)
{
   //オブジェクトを作成する。
   long chartId = ChartID();
   string name = OBJECT_NAME + TimeToStr(time);
   return ObjectDelete(chartId, name);
}

//+------------------------------------------------------------------+