2016年10月7日金曜日

[MT4インジケータ]矢印表示機能付きRCI

ハーモニックパターントレードと一緒にタイミングを計るために使っている矢印表示機能付きRCIです。



詳細は次の記事をご覧ください。

ハーモニックパターン トレード手法 RCIと組み合わせてタイミングを計る(研究中です)
http://mt4program.blogspot.jp/2016/07/rci.html

ぱたぱた忙しいので、ソースコードだけとりあえず公開します。
そのうちFX-ONにビルドファイルアップします。
RCI(8)が±60のラインをまたいだときに矢印が出るように初期値ではなっています。



//------------------------------------------------------------------
// RCI矢印

#property copyright "Copyright 2016,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.10"
#property strict
#property indicator_separate_window
#property indicator_minimum -100
#property indicator_maximum 100

#include <Object.mqh>
#include <Arrays/ArrayObj.mqh>

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

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

#property indicator_label1  "RCI1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrAqua
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

#property indicator_label2  "RCI2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_DOT
#property indicator_width2  1

input int Rci1Period = 8;    // RCI1期間(0 <= value 0表示しない)
input int Rci2Period = 12;   // RCI2期間(0 <= value 0表示しない)
input double SmoothAlfa = 0.7;// 平滑化パラメータ(0 < value <=1)

input bool ShowOverThreshold = false; //RCI1がSignalThresholdを超えた場合サインを表示する
input bool ShowUnderThreshold = true; //RCI1がSignalThresholdを下回った場合場合サインを表示する
input bool ShowMainSubCross = false; //RCI1とRCI2のクロスでサインを表示する。

input bool IsNearNotDisplay = true; // RCI2/2期間未満で同じ方向のシグナルは表示しない

input double SignalThreshold = 60; // 買いシグナル閾値(0 < value < 100 売りシグナル=-value)
input ENUM_OBJECT BuyObjectType = OBJ_ARROW_BUY;   //買い時オブジェクトタイプ
input ENUM_OBJECT SellObjectType = OBJ_ARROW_SELL; //売り時オブジェクトタイプ

input int BuyArrowCode = 233; //買い時矢印形状 233上矢印、161丸、
input int SellArrowCode = 234; //売り時矢印形状 234下矢印、161丸
input color BuyColor = C'128,128,255';
input color SellColor = C'255,128,128';

input bool IsClosePosition = true;  // オブジェクトの位置を終値基準にする場合True、高値安値基準にする場合false

// バッファー
double rci1[];
double rci2[];

#define OBJECT_NAME "RCIOBJ"

//------------------------------------------------------------------
//初期化
int OnInit()
{
   // 短縮名を設定
   string shortName = "RCI AR (";
   shortName += 
      IntegerToString(Rci1Period) + "," + IntegerToString(Rci2Period) + ")";
   IndicatorShortName(shortName);

   int count = 0;
   SetIndexBuffer(count++, rci1);
   SetIndexBuffer(count++, rci2);
   
 IndicatorSetDouble(INDICATOR_LEVELVALUE, 0, SignalThreshold);
 IndicatorSetDouble(INDICATOR_LEVELVALUE, 1, -SignalThreshold);

   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[])            //スプレット
{

   CArrayObj arrays1;
   CArrayObj arrays2;

   for( int i = rates_total - prev_calculated - 1 ; i >= 0; i-- )
   {
      if( i >= rates_total - 2 || i >= rates_total - Rci1Period - 1|| i >= rates_total - Rci2Period  - 1)
      {
         rci1[i] = 0 ;
         rci2[i] = 0 ;
         continue;
      }
      
      for(int j = 0; j < Rci1Period || j < Rci2Period; j++)
      {
         //CIndexPricePierの生成
         CIndexPricePier *pier = new CIndexPricePier();
         pier.Price = close[i + j];
         pier.Index = j + 1;

         if( j < Rci1Period ) arrays1.Add(pier);
         if( j < Rci2Period ) arrays2.Add(pier);
      }

      //ソート
      arrays1.Sort();
      arrays2.Sort();

      // (x順位-y順位)^2合計の計算
      int diff1 = 0;      
      int diff2 = 0;    

      for(int j = 0; j < Rci1Period || j < Rci2Period; j++)
      {
         if( j < Rci1Period )
         {
            CIndexPricePier *pier = (CIndexPricePier *)arrays1.At(j);
            diff1 += (int)MathPow((j + 1) - pier.Index, 2);
         }
         if( j < Rci2Period )
         {
            CIndexPricePier *pier = (CIndexPricePier *)arrays2.At(j);
            diff2 += (int)MathPow((j + 1) - pier.Index, 2);
         }
      }
      // RCIの計算
      if( Rci1Period > 0 ) rci1[i] = SmoothAlfa * (1 - 6 * diff1 / (MathPow(Rci1Period, 3) - Rci1Period)) * 100 + (1 - SmoothAlfa ) * rci1[i + 1];
      if( Rci2Period > 0 ) rci2[i] = SmoothAlfa * (1 - 6 * diff2 / (MathPow(Rci2Period, 3) - Rci2Period)) * 100 + (1 - SmoothAlfa ) * rci2[i + 1];
      
      // オブジェクトはClearメソッド内でdeleteが呼ばれる。
      arrays1.Clear();
      arrays2.Clear();

      DeleteArrawObject(time[i]);
      
      int doubleRci2 = Rci2Period / 2 ;
      int mainsubCrossBeforeBuy = doubleRci2 + 1;
      int mainsubCrossBeforeSell =  doubleRci2 + 1;
      int overThresholdBuy =  doubleRci2 + 1;
      int overThresholdSell =  doubleRci2 + 1;
      int underThresholdBuy =  doubleRci2 + 1;
      int underThresholdSell =  doubleRci2 + 1;
      
      if( IsNearNotDisplay && (ShowMainSubCross || ShowOverThreshold || ShowUnderThreshold) )
      {
         for( int j = 1; j < doubleRci2 && i + j + 1 < rates_total - 1; j++ )
         {
            if( ShowMainSubCross)
            {
               if( rci1[i + j] < rci2[i + j] && rci1[i + j + 1] >= rci2[i + j + 1] && rci2[i + j] > SignalThreshold && mainsubCrossBeforeSell > doubleRci2)
               {
                  mainsubCrossBeforeSell = j;
               }
               if( rci1[i + j] > rci2[i + j] && rci1[i + j + 1] <= rci2[i + j + 1] && rci2[i + j] < -SignalThreshold && mainsubCrossBeforeBuy > doubleRci2)
               {
                  mainsubCrossBeforeBuy = j;
               }
            }
            if( ShowOverThreshold )
            {
               if( rci1[i + j] < -SignalThreshold && rci1[i + j + 1] >= -SignalThreshold && overThresholdBuy > doubleRci2)
               {
                  overThresholdBuy = j;
               }
               if( rci1[i + j] > SignalThreshold && rci1[i + j + 1] <= SignalThreshold && overThresholdSell > doubleRci2 )
               {
                  overThresholdSell = j;
               }
            }
            if( ShowUnderThreshold )
            {
               if( rci1[i + j] > -SignalThreshold && rci1[i + j + 1] <= -SignalThreshold && underThresholdBuy > doubleRci2)
               {
                  underThresholdBuy = j;
               }
               if( rci1[i + j] < SignalThreshold && rci1[i + j + 1] >= SignalThreshold && underThresholdSell > doubleRci2 )
               {
                  underThresholdSell = j;
               }
            }
         }
      }

      if( ShowMainSubCross )
      {
         if( rci1[i] < rci2[i] && rci1[i + 1] >= rci2[i + 1] && rci2[i] > SignalThreshold && mainsubCrossBeforeSell > doubleRci2)
         {
            CreateArrawObject(SellObjectType, time[i], open[i], close[i], high[i], low[i]);
         }
         if( rci1[i] > rci2[i] && rci1[i + 1] <= rci2[i + 1] && rci2[i] < -SignalThreshold && mainsubCrossBeforeBuy > doubleRci2)
         {
            CreateArrawObject(BuyObjectType, time[i], open[i], close[i], high[i], low[i]);
         }
      }
      if( ShowOverThreshold )
      {
         if( rci1[i] < -SignalThreshold && rci1[i + 1] >= -SignalThreshold && overThresholdBuy > doubleRci2)
         {
            CreateArrawObject(BuyObjectType, time[i], open[i], close[i], high[i], low[i]);
         }
         if( rci1[i] > SignalThreshold && rci1[i + 1] <= SignalThreshold && overThresholdSell > doubleRci2 )
         {
            CreateArrawObject(SellObjectType, time[i], open[i], close[i], high[i], low[i]);
         }
      }
      if( ShowUnderThreshold )
      {
         if( rci1[i] > -SignalThreshold && rci1[i + 1] <= -SignalThreshold && underThresholdBuy > doubleRci2)
         {
            CreateArrawObject(BuyObjectType, time[i], open[i], close[i], high[i], low[i]);
         }
         if( rci1[i] < SignalThreshold && rci1[i + 1] >= SignalThreshold && underThresholdSell > doubleRci2 )
         {
            CreateArrawObject(SellObjectType, time[i], open[i], close[i], high[i], low[i]);
         }
      }

   }

   return(rates_total - 1);
}

//------------------------------------------------------------------
//売買矢印オブジェクトを生成する。
bool CreateArrawObject(
   ENUM_OBJECT objectType,  //オブジェクトの種類
   datetime time,           //表示時間(横軸)
   double open,            //始値
   double close,           //終値
   double high,            //高値
   double low              //安値
   )
{
   //オブジェクトを作成する。
   long chartId = ChartID();
   
   double price = IsClosePosition ? close : (objectType == BuyObjectType ? high : low);
    
   string name = OBJECT_NAME + TimeToStr(time);
   if( !ObjectCreate(chartId, name, objectType, 0, time, price) )
   {
      return false;
   }
   ObjectSetInteger(chartId, name, OBJPROP_HIDDEN, true);
   ObjectSetInteger(chartId, name, OBJPROP_COLOR, objectType == BuyObjectType ? BuyColor : SellColor);
   ObjectSetInteger(chartId, name, OBJPROP_ARROWCODE, objectType == BuyObjectType ? BuyArrowCode : SellArrowCode);
   
   int anchor;
   
   if( IsClosePosition )
   {
      anchor = open < close ? ANCHOR_BOTTOM : ANCHOR_TOP ;
   }
   else
   {
      anchor = objectType == BuyObjectType ? ANCHOR_BOTTOM : ANCHOR_TOP;
   }
   
   ObjectSetInteger(chartId, name, OBJPROP_ANCHOR, anchor);
   return true;
}

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


#define CINDEX_PRICE_PIER_TYPE 12566
//------------------------------------------------------------------
// 価格インデックスペア
class CIndexPricePier : public CObject
{
public:

   //------------------------------------------------------------------
   //価格
   double Price;
   
   //------------------------------------------------------------------
   //インデックス
   int Index;

   //------------------------------------------------------------------
   //タイプ識別子取得
   virtual int Type(void) const { return(CINDEX_PRICE_PIER_TYPE); }

   //------------------------------------------------------------------
   //比較
   // return 1 nodeより小さい 0 nodeと等しい -1 nodeより大きい
   virtual int Compare(const CObject *node,const int mode=0) const 
   { 
      if(node == NULL || node.Type() != CINDEX_PRICE_PIER_TYPE )
      {
         return 0;
      }
      
      CIndexPricePier* target = (CIndexPricePier*)node;
      
      if( Price < target.Price ) return 1;
      if( Price > target.Price ) return -1;
      return(0);
   }
};

「MT4でFXを勝ち抜く研究をするブログ」で公開している無料インジケータは、こちらの一覧から。
インジケータ一覧

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

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

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