昨日の続きです。「MT4プログラムの小ネタ 関数で複数の値を戻す。」のテクニックを使ってStochasticOnArrayという任意のdouble型配列のストキャスを求める関数を作成したいと思います。
StockRSIの様にモメンタム系の指標に対して作成すると、勢いの変化をとらえることができます。
モメンタム系の指標にかたっぱしから突っ込むのに毎回コード書いているのは面倒になので関数化してみました。iXXXOnArrayの流儀に従って毎回必要な値を計算するアルゴリズムとしています。インジケーターで使用する場合には無駄になるのですが、EA内で呼び出される場合はこちらの方が都合が良かったということもあります。
#property copyright "Copyright 2015, Daisuke"
#property link "http://mt4program.blogspot.jp/"
#property strict
// メイン・シグナル構造体
struct MainSignalValue
{
//メイン
double main;
//シグナル
double signal;
};
//配列に対するストキャス値を求める。
MainSignalValue StochasticOnArray(
const double &array[], // 元データ
int total, // 総数
int kPeriod, // Kライン期間
int dPeriod, // Dライン期間
int slowing, // スローイング
ENUM_MA_METHOD method, // 移動平均手法
int shift // シフト
)
{
// 返却値
MainSignalValue value ;
value.main = 0 ;
value.signal = 0;
// バッファ長
int length = dPeriod + slowing - 1;
//開始位置
if ( kPeriod >= total - shift - length) return value;
double lowesBuffer[];
double highesBuffer[];
ArrayResize(lowesBuffer, length);
ArrayResize(highesBuffer, length);
for( int i = shift; i < shift + length; i++ )
{
// 高値・安値判定
double dmin = 1000000.0;
double dmax = -1000000.0;
for (int k = i; k < i + kPeriod; k++)
{
if (dmin > array[k]) dmin = array[k];
if (dmax < array[k]) dmax = array[k];
}
lowesBuffer[i - shift] = dmin;
highesBuffer[i - shift] = dmax;
}
double main[];
ArrayResize(main, dPeriod);
ArraySetAsSeries(main, true);
// メインサイクル
for (int i = 0; i < dPeriod && !IsStopped(); i++)
{
double sumlow = 0.0;
double sumhigh = 0.0;
for (int k = i; k < slowing + i; k++)
{
sumlow += array[k + shift] - lowesBuffer[k];
sumhigh += highesBuffer[k] - lowesBuffer[k];
}
main[i] = sumhigh == 0.0 ? 100.0 : sumlow * 100.0 / sumhigh ;
}
value.main = main[0];
//--- シグナル
value.signal = iMAOnArray(main, dPeriod, dPeriod, 0, method, 0);
return value;
}
「ストキャスティクスRSI オシレーターを作成してみた。」からOnCalculate部分をStochasticOnArrayを使用したバージョンです。同じところは省略してあります。ぜひ前の記事のOnCalculate部分と比較してみてください。すっきりしていることがわかると思います。
//------------------------------------------------------------------
// ストキャスティクス RSI オシレーター
#property copyright "Copyright 2015, Daisuke"
#property link "http://mt4program.blogspot.jp/"
#property version "1.00"
#property strict
#include <Custom/MathFunctions.mqh>
// グラフ定義部分やOnInitはかわっていないので省略
//------------------------------------------------------------------
//計算イベント
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[]) //スプレット
{
ArraySetAsSeries( rsiBuffer, true );
//元となる値を計算する。
for( int i = (rates_total - prev_calculated - 1); i>=0 ; i-- )
{
rsiBuffer[i] = iRSI(Symbol(), PERIOD_CURRENT, RSIPeriod, RSIPrice, i);
}
//元となる値を計算する。
for( int i = (rates_total - prev_calculated - 1); i>=0 ; i-- )
{
MainSignalValue stc = StochasticOnArray(rsiBuffer, rates_total, InpKPeriod, InpDPeriod, InpSlowing, MODE_SMA, i);
mainBuffer[i] = stc.main;
signalBuffer[i] = stc.signal;
}
return (rates_total - 1);
}
このようにたびたび使う所は関数化しておくことをおすすめします。きれいなプログラムを作成しておくとEAにいざトラブルが発生した場合や新しい機能を追加したい場合などでの作業時間を少なくする効果があります。ちなみにソフトウェア業界的には「保守性が高い」とか表現します。関数化は保守性の高いプログラムの第一歩となります。
余談ですがStockRSIは作成後バイナリオプションの指標として使用していますが、EU時間帯であれば7割程度の勝率を維持できます。バイナリオプションでは勝率6割をこえるかどうかが+になる重要なポイントとなりますのでかなり使える印象です。