まぁEAに組み込もうと思うとアルゴリズム知ったほうがいいし作るか!ということで、作ってしまいました。
RCI(Rank Correlation Index)は順位相関係数を表示したものです。順位相関係数とは時間の順位と価格の順位だけの相関をといったものです。連続して上昇すると上に、下降すると下になります。価格差を全く意識しない場合のインデックス値になります。
ざっくり説明すると、RCI(5)において、5本連続で上昇すると100、5本連続で下降すると-100になります。その際、上昇時が100pipsで下降時が10pipsでも100と-100になります。
この価格差を意識しないというところが、利点でもあり欠点でもあります。時間的な価格推移をみて例えば8時間も上がり続けたらいい加減いっぱいだろう?とか、長期で上がっている場合はトレンドだろう?といったことを推測します。
長期RCIが0より大きい場合で、短期RCIが0より小さい場合は買い、長期RCIが0より小さい場合で、短期RCIが0より大きい場合は売りといった形の戦略が基本のようです。
EAに組み込んでみてのテストはまだしていません。
ちょっとこのままでは、シグナルとして扱いにくい部分もあるため、短期中期長期のRCIをDrawSimpleLineやPathFinderMAのように差分で見たりすると、EAで扱いやすい数値になるかもしれませんね~。
プログラム的には、CObjectを使用しています。MQLのクラスは遅くいのであまりループ処理の中では使いたくないのですが、クイックソートを使って単純化したかったため、横着して使ってしまいました。
CObjectを継承したCIndexPricePierクラスを作成しています。CIndexPricePierには価格と時間をIndex化した変数を持たせています。
RCIの計算数分だけ、CIndexPricePierを生成してCArrayObjに追加します。
CArrayObjにはSort関数がついているため、CArrayObjのSortにて価格の順位を出しています。
後はRCIの計算式であるスピアマンの順位相関係数に突っ込んでみました。
RCI = (1 - 6 * D / (n ^ 3 - n)) * 100
D = (X順位 - Y順位)^2の合計
MT4開発日記で公開している無料インジケータは、こちらの一覧から。
インジケータ一覧
Twitterもよろしくお願いします。
https://twitter.com/mt4program
ブログランキングにご協力よろしくお願いします。m(._.)m
お約束ですが、本ブログは、投資に対する利益を約束する物ではありません。最終的には自己責任によるご判断よろしくお願いいたします。
//------------------------------------------------------------------
// RCI
#property copyright "Copyright 2016, Daisuke"
#property link "http://mt4program.blogspot.jp/"
#property version "1.00"
#property strict
#property indicator_separate_window
#property indicator_minimum -100
#property indicator_maximum 100
#property indicator_level1 80
#property indicator_level2 -80
#include <Object.mqh>
#include <Arrays/ArrayObj.mqh>
//バッファーを指定する。
#property indicator_buffers 4
//プロット数を指定する。
#property indicator_plots 4
#property indicator_label1 "RCI1"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrIndianRed
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1
#property indicator_label2 "RCI2"
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrAqua
#property indicator_style2 STYLE_SOLID
#property indicator_width2 1
#property indicator_label3 "RCI3"
#property indicator_type3 DRAW_LINE
#property indicator_color3 clrYellow
#property indicator_style3 STYLE_SOLID
#property indicator_width3 1
#property indicator_label4 "RCI4"
#property indicator_type4 DRAW_LINE
#property indicator_color4 clrGreen
#property indicator_style4 STYLE_SOLID
#property indicator_width4 1
input int Rci1Period = 8; // RCI1期間(0 <= value 0表示しない)
input int Rci2Period = 12; // RCI2期間(0 <= value 0表示しない)
input int Rci3Period = 34; // RCI3期間(0 <= value 0表示しない)
input int Rci4Period = 48; // RCI4期間(0 <= value 0表示しない)
input int Shift = 0; // 表示シフト
// バッファー
double rci1[];
double rci2[];
double rci3[];
double rci4[];
//------------------------------------------------------------------
//初期化
int OnInit()
{
// 短縮名を設定
string shortName = "RCI (";
shortName +=
IntegerToString(Rci1Period) + "," + IntegerToString(Rci2Period)
+ "," + IntegerToString(Rci3Period)+ "," + IntegerToString(Rci4Period) + ")";
IndicatorShortName(shortName);
int count = 0;
SetIndexBuffer(count++, rci1);
SetIndexBuffer(count++, rci2);
SetIndexBuffer(count++, rci3);
SetIndexBuffer(count++, rci4);
for( int i = 0; i < count; i++)
{
SetIndexShift(i, Shift + 1);
}
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[]) //スプレット
{
CArrayObj arrays1;
CArrayObj arrays2;
CArrayObj arrays3;
CArrayObj arrays4;
for( int i = rates_total - prev_calculated - 1 ; i >= 0; i-- )
{
if( i >= rates_total - 2 ) continue;
if( i >= rates_total - Rci1Period - 1|| i >= rates_total - Rci2Period - 1 || i >= rates_total - Rci3Period - 1|| i >= rates_total - Rci4Period - 1)
{
continue;
}
for(int j = 0; j < Rci1Period || j < Rci2Period || j < Rci3Period || j < Rci4Period; 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);
if( j < Rci3Period ) arrays3.Add(pier);
if( j < Rci4Period ) arrays4.Add(pier);
}
//ソート
arrays1.Sort();
arrays2.Sort();
arrays3.Sort();
arrays4.Sort();
// (x順位-y順位)^2合計の計算
int diff1 = 0;
int diff2 = 0;
int diff3 = 0;
int diff4 = 0;
for(int j = 0; j < Rci1Period || j < Rci2Period || j < Rci3Period || j < Rci4Period; 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);
}
if( j < Rci3Period )
{
CIndexPricePier *pier = (CIndexPricePier *)arrays3.At(j);
diff3 += (int)MathPow((j + 1) - pier.Index, 2);
}
if( j < Rci4Period )
{
CIndexPricePier *pier = (CIndexPricePier *)arrays4.At(j);
diff4 += (int)MathPow((j + 1) - pier.Index, 2);
}
}
// RCIの計算
if( Rci1Period > 0 ) rci1[i + 1] = (1 - 6 * diff1 / (MathPow(Rci1Period, 3) - Rci1Period)) * 100;
if( Rci2Period > 0 ) rci2[i + 1] = (1 - 6 * diff2 / (MathPow(Rci2Period, 3) - Rci2Period)) * 100;
if( Rci3Period > 0 ) rci3[i + 1] = (1 - 6 * diff3 / (MathPow(Rci3Period, 3) - Rci3Period)) * 100;
if( Rci4Period > 0 ) rci4[i + 1] = (1 - 6 * diff4 / (MathPow(Rci4Period, 3) - Rci4Period)) * 100;
// オブジェクトはClearメソッド内でdeleteが呼ばれる。
arrays1.Clear();
arrays2.Clear();
arrays3.Clear();
arrays4.Clear();
}
return(rates_total - 1);
}
#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);
}
};