2015年5月6日水曜日

MT4プログラミング StochasticOnArrayを作ってみた。

StochRSIOnArray.png

昨日の続きです。「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割をこえるかどうかが+になる重要なポイントとなりますのでかなり使える印象です。


4 件のコメント:

  1. メロンパン氏2017年5月21日 10:36

    こんにちわ。
    iStocasticOnArray関数のコードを教えていただけませんでしょうか?
    この関数を呼び出したときは、rates_total分のループがその都度行われる仕様ですか?

    返信削除
    返信
    1. StocasticOnArrayのコードは、記事内にある一つ目のコードです。二つ目のコードは使い方となります。
      関数は指定シフト値のみしか計算しない作りです。一個しか値を返しません。


      削除
  2. メロンパン氏2017年5月31日 1:07

    すみません。お返事遅れてしまいました。
    前回スマホから閲覧していたため、公開していただいているのに、気づきませんでした( ノД`)
    大変分かりやすいコードをありがとうございます。検証に利用させて頂きます。
    rates_totalの件は、RSIOnArrayの値がおかしくなってしまう問題に悩まされていたので質問させてもらいました。(結局あきらめました(笑))

    返信削除
    返信
    1. rates_total付近では、値がおかしくなってしまいますので、rate_total-RSI期間-1のインデックスからiRsiOnArrayを呼び出す必要がありますよー?

      ともあれ、参考になれば何よりです。今後ともよろしくお願いします。

      削除