2015年5月26日火曜日

MT4プログラミング いまいち使えない子のCArrayDoubleを改造する。CArrayDoubleで移動平均

今日も小ネタです。

Build600からオブジェクト指向に対応しているMQL4です。
オブジェクト指向対応版の配列クラスCArrayDoubleがコードも合わせてMT4に添付されています。

配列操作が便利にはなるのですが、標準関数であるiMAOnArrayの引数が当然のごとくdouble[]を要求してくるのでCArrayDoubleで値を保持してしまうと移動平均が取れないといった問題があります。

オブジェクト指向の機能として継承という機能があります。CArrayDbouleを拡張してiMAOnArrayによる移動平均を計算できるようにしたいと思います。

継承についてはWikiの説明を見てください。継承 (プログラミング)

//------------------------------------------------------------------
// CArrayDouble 各種計算追加クラス
#property copyright "Copyright 2015,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict

#include <Arrays/ArrayDouble.mqh>

//------------------------------------------------------------------
// CArrayDouble 各種計算追加クラス
class CCustomArrayDouble : public CArrayDouble
{
private:

public:
//------------------------------------------------------------------
// コンストラクタ
CCustomArrayDouble();

//------------------------------------------------------------------
// デストラクタ
~CCustomArrayDouble();

//------------------------------------------------------------------
// 移動平均を取得する。
double GetMa(
int period,             // 移動平均期間
int maShift,            // 移動平均シフト
ENUM_MA_METHOD method,  // 移動平均種別
int shift               // シフト
);
};

//------------------------------------------------------------------
// コンストラクタ
CCustomArrayDouble::CCustomArrayDouble() : CArrayDouble()
{
ArraySetAsSeries(m_data, true);
}

//------------------------------------------------------------------
// デストラクタ
CCustomArrayDouble::~CCustomArrayDouble()
{
}

//------------------------------------------------------------------
// 移動平均を取得する。
double CCustomArrayDouble::GetMa(
int period,             // 移動平均期間
int maShift,            // 移動平均シフト
ENUM_MA_METHOD method,  // 移動平均種別
int shift               // シフト
)
{
// 高速化のため単純移動平均は自力で計算する。
if( method == MODE_SMA )
{
double sum = 0;
int count = 0 ;
for( int i = shift; i < shift + period && i < Total(); i++ )
{
sum += At(i);
count ++ ;
}
return count == 0 ? 0 : sum / count;
}
else
return iMAOnArray(m_data, 0, period, maShift, method, shift);
}


プログラム的には移動平均を求める関数を追加した形となります。コンストラクタで、 ArraySetAsSeries(m_data, true);
を呼び出しています。これは、MT4のインジケータ等のバッファが基本シリーズ配列なためインデックスに対する動きを合わせる為に呼び出しています。iMAOnArrayの動作が変わります。iMAOnArrayですが結構重いです。配列に対して特定インデックスの単純移動平均を求めるような場合は総和をnで割った方が速度が速いため自力で計算しています。10倍ぐらい早くなります。バックテストなどでは結構効いてきます。

使い方はこんな感じになります。CArrayDoubleの機能を保持したまま、移動平均を求める機能を追加しています。継承の典型ですね。
CCustomArrayDouble buffer;
buffer.Resize(10);
buffer.Add(1.0);
buffer.Add(1);
//...略
double ma = buffer.GetMa(10, 0, MODE_SMA, 0);


まぁMT4のプログラムでここまでする必要があるのか?と言われると、一回きりなら不要と答えます。長々と作っていく場合こーいったライブラリを整理しておくと将来的な時間削減につながると思って対応しています。地道な作業の積み重ねですね。