2015年5月8日金曜日

今度は移動平均3本で判定! 少し見にくい・・けど? PathFinderMAを作ってみた。

昨日の「シンプルだけど効果あり!MT4でDrawSimpleLineインジケータを作ってみた。」は移動平均4本の差でしたが、今度は3本で判断するインジケータ PathFinderMAを作ってみました。

PathFinderMA.PNG

短期移動平均の一本前差と、中期-長期移動平均差を眺めて判定するインジケータです。
ヒストグラム形式で出ているのが短期移動平均の一本前差です。今回はわかりやすいように、短期移動平均差が上昇の場合は水色、下降の場合は赤色で描画しています。黄色い線が中期移動平均-長期移動平均です。
見方としては、黄色い線が0以上の箇所で上昇から下降に転じた際、同時に短期の短期移動平均差が下降している場合は売り、黄色い線が0以下の箇所で下降から上昇に転じた場合は買いとなります。

うーん?少々短期の移動平均差が見えにくいですよね。短期移動平均差が0付近をうろうろしている場合は取引しない方がよさそうです。明確に上下しているときのみ取引といった形になるかと思います。
短期移動平均差をさらに移動平均で表現したほうがもしかしたらわかりやすいかもしれません。

このインジケータも移動平均ベースのモメンタムを表現していますので、ダイバージェンス現象(高値/安値を更新しているのにもかかわらずインジケータ上では前回位置より低い位置にピークが来ること)が見て取れます。組み合わせて判断するのがよさそうに思われます。

//------------------------------------------------------------------
// PathFinderMA

#property copyright "Copyright 2015,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict
#property indicator_separate_window

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

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

// 短期前足差 上げ
#property indicator_label1  "SHORT UP"
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  clrAqua
#property indicator_style1  STYLE_SOLID

// 短期前足差 下げ
#property indicator_label2  "SHORT DOWN"
#property indicator_type2   DRAW_HISTOGRAM
#property indicator_color2  clrIndianRed
#property indicator_style2  STYLE_SOLID

// 中期-長期
#property indicator_label3  "LINE"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrYellow
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1


// 入力パラメータ 短期移動平均期間
input int MaShortPeriod = 6;
// 入力パラメータ 中期移動平均期間
input int MaMiddlePeriod = 9;
// 入力パラメータ 長期移動平均期間
input int MaLongPeriod = 18;

//入力パラメータ 移動平均種別
input ENUM_MA_METHOD MaMethod = MODE_SMA;

//入力パラメータ 適用価格
input ENUM_APPLIED_PRICE MaPrice = PRICE_CLOSE;

// バッファー
double shortUpBuffer[];
double shortDownBuffer[];
double lineBuffer[];

//------------------------------------------------------------------
//初期化
int OnInit()
{
// 短縮名を設定
string shortName = "PFMA (";
shortName += IntegerToString(MaShortPeriod) + "," ;
shortName += IntegerToString(MaMiddlePeriod) + ",";
shortName += IntegerToString(MaLongPeriod) + ")";
IndicatorShortName(shortName);

SetIndexBuffer(0, shortUpBuffer);
SetIndexBuffer(1, shortDownBuffer);
SetIndexBuffer(2, lineBuffer);

SetIndexDrawBegin(0, MaLongPeriod);
SetIndexDrawBegin(1, MaLongPeriod);
SetIndexDrawBegin(2, MaLongPeriod);

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[])            //スプレット
{
for( int i = rates_total - prev_calculated - 1 ; i >= 0; i-- )
{
lineBuffer[i] = iMA(NULL, PERIOD_CURRENT, MaMiddlePeriod, 0, MaMethod, MaPrice, i) - iMA(NULL, PERIOD_CURRENT, MaLongPeriod, 0, MaMethod, MaPrice, i);

if( i == rates_total - 1 )
{
shortUpBuffer[i] = 0 ;
shortDownBuffer[i] = 0 ;
}
else
{
double beforeDiff = shortUpBuffer[i + 1] == 0 ? shortDownBuffer[i + 1] : shortUpBuffer[i + 1] ;
double shortDiff = iMA(NULL, PERIOD_CURRENT, MaShortPeriod, 0, MaMethod, MaPrice, i) - iMA(NULL, PERIOD_CURRENT, MaShortPeriod, 0, MaMethod, MaPrice, i + 1);

if( shortDiff < beforeDiff )
{
shortUpBuffer[i] = 0;
shortDownBuffer[i] = shortDiff;
}
else
{
shortUpBuffer[i] = shortDiff;
shortDownBuffer[i] = 0;
}
}
}

return(rates_total - 1);
}


ここ最近、モメンタム系オシレータのインジばかり作成していますので、次はレンジブレイク系のインジ作成する予定です。

2015年5月7日木曜日

雑談 結局PC買うときは何を気にすればいいの?

SSD.PNG

PCを新調したい!というときに、着目するべき点についてです。
PCというのは

CPU
メモリ
記録媒体
グラフィックカード
ケース

の組み合わせになります。
CPUからグラフィックカードまでがPCの性能を左右します。

ケースは設置場所や見た目を左右します。

ここ数年のPC購入に関する着目点をまとめたいと思います。
・CPU
 ここ数年ほとんど性能向上はしていません。
 通常使う用途でCore iシリーズでしたら、ほぼ体感速度に影響を与えません。予算と性能で迷う場合はまずここを削ってください。通常時20%も使っていません。瞬間値で高くなることはありますが、ほんと無視できる時間です。とはいってもCeleronとCore iシリーズにはそれなりの差があるため、Core iとついている物を選びます。Coreも3,5,7とあり、さらにそれぞれ細分化されていますが、通常用途ではCore i3で十分です。デザインや開発などといったお仕事をする場合はCore i5を選択します。Core i7は洋ゲーかAdobe After Effectsなどを使う真のプロフェッショナル向けです。
 ちなみにCore i3,5,7の違いは主に論理コア数というやつの違いになります。同時にいろんな計算ができる数が多いほどお値段が高くなります。画像処理やゲーム、プログラムのビルドなど同時に色々な計算をやらせるソフトには効果が高いですが、それ以外では効果が表れません。

・メモリ
 用途によって異なります。仮想OS、グラフィックソフト、洋ゲーといった単語に引っかかる使用方法をするのであれば16GB、引っかからないのなら8GBを選択します。Officeソフトしか使わない!という前提でしたら4GBでも大きな問題はありませんが、長い事使うのであれば、それほど高くないですし8GBまでは搭載することをお勧めします。

・記録媒体
 体感的な速度にもっとも影響を与える項目です。
 20万オーバーのXEONとHDDで使用する場合より、Core i3にSSDを搭載した方が体感速度が速いです。記録媒体はミリ秒オーダーの速度ですが、CPUの速度はナノ秒オーダーです。1ナノが10ナノになったところでたいして気になりませんが、1ミリが10ミリになると大変気になります。
 近年のPC購入は、自分が必要とする容量のSSDを選択することから始まるといって過言ではありません。
 ですので最低256GB SSDをベースに、大量の写真や動画を扱う場合には2TBほどのHDDを組み合わせるといった選択になります。さらにSSDの特徴として空き容量が多いほど寿命が長いという事があります。できれば512GBをお勧めします。

・グラフィックカード
 ここは外付けグラフィックカードという意味になります。ここはゲームか、Adobe系のグラフィックソフトを扱うかどうかにかかってきます。
 CPUにも内臓されています。ゲームやグラフィックソフトを扱わないのでしたらCPUに搭載されている物で十分です。GeForceとかRedion搭載!とか書かれていないものを選択します。

・ケース
 デスクトップやノートPCなど外観です。それぞれ、さまざまな種類があるので、予算の範囲内で一番見た目に問題がなさそうなのを好みで選ぶことになります。

さて・・どうでしたでしょうか?
長々と書きましたが結論はCPU?そんなのどうでもいい! とにかくSSDに予算を突っ込め!という事です。(笑)
HDDとSSDでは、はっきりわかるぐらい体感速度が異なります。実際私も古いCore2DuoのPCにSSDをつけて延命したりしています。9年前のPCでもSSDに変えるだけでOffice用途には十分使えるPCに生まれ変わります。いかに今までHDDに足を引っ張られていたのかわかりますね。

 ちなみにMT4開発ではバックテストに大量のディスクアクセスが伴います。MT4開発だけを考えるなら、高速なSSDを搭載したPCがおすすめです。CPUは一つのコアだけ50%ほど使用して後は10%~20%を使用しています。Phenom2 X4という6年前の少々古いCPUでもこのレベルです。今買うのならCore i3で十分と思われます。
 ただしディスクアクセスがものすごく高速になるとCPUの使用率も上がる傾向があるため、もし超高速(Intel SSD 750とか)SSDを搭載する場合にiCore5にしましょう。

 あー。Intel SSD 750搭載PCを私も新調したい・・。


シンプルだけど効果あり!MT4でDrawSimpleLineインジケータを作ってみた。

DSL.PNG

分かりやすくて効果がありそうなインジケータということで、DrawSimpleLineを実装してみました。主にグラフが交差したところで売買するインジケータとなります。

DrawSimpleLineとは短い期間同士の移動平均と、長い期間同士の移動平均の差を描画します。移動平均の収束と拡散を判断するオシレータです。考え方はMACDと似ていますが、MACDは二つの移動平均差から算出しますが、こちらは4つの移動平均の収束拡散を示しています。コードはかなり単純で、移動平均の差をそれぞれ算出するだけです。

//------------------------------------------------------------------
// Draw Simple Line

#property copyright "Copyright 2015,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict
#property indicator_separate_window

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

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

// MA1-MA2
#property indicator_label1  "LINE1"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrAqua
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

// MA3-MA4
#property indicator_label2  "LINE2"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrIndianRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

// 入力パラメータ 移動平均1期間
input int Ma1Period = 5;
// 入力パラメータ 移動平均2期間
input int Ma2Period = 10;
// 入力パラメータ 移動平均3期間
input int Ma3Period = 7;
// 入力パラメータ 移動平均4期間
input int Ma4Period = 13;

//入力パラメータ 移動平均種別
input ENUM_MA_METHOD MaMethod = MODE_SMA;

//入力パラメータ 適用価格
input ENUM_APPLIED_PRICE MaPrice = PRICE_CLOSE;

// バッファー
double diff1Buffer[];
double diff2Buffer[];

//------------------------------------------------------------------
//初期化
int OnInit()
{
// 短縮名を設定
string shortName = "DSL (";
shortName += IntegerToString(Ma1Period) + "-" + IntegerToString(Ma2Period) + ",";
shortName += IntegerToString(Ma3Period) + "-" + IntegerToString(Ma4Period) + ")";
IndicatorShortName(shortName);

SetIndexBuffer(0, diff1Buffer);
SetIndexBuffer(1, diff2Buffer);

SetIndexDrawBegin(0, Ma2Period);
SetIndexDrawBegin(1, Ma4Period);

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[])            //スプレット
{
for( int i = rates_total - prev_calculated - 1 ; i >= 0; i-- )
{
diff1Buffer[i] = iMA(NULL, PERIOD_CURRENT, Ma1Period, 0, MaMethod, MaPrice, i) - iMA(NULL, PERIOD_CURRENT, Ma2Period, 0, MaMethod, MaPrice, i);
diff2Buffer[i] = iMA(NULL, PERIOD_CURRENT, Ma3Period, 0, MaMethod, MaPrice, i) - iMA(NULL, PERIOD_CURRENT, Ma4Period, 0, MaMethod, MaPrice, i);
}

return(rates_total - 1);
}


一方的な相場ではだましのシグナルも発生しますが、その場合は再度クロスしたところで早めに損切してクロスした方向へ再度ポジションをとるという戦略がよさそうです。あと小さな値動きですと、何回もクロスしますのである程度の振幅が発生した場合だけ取引するというのが有効に思われます。



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


2015年5月5日火曜日

MT4プログラムの小ネタ 関数で複数の値を戻す。

たとえば、ストキャス値を計算する関数の場合、メインとシグナルの二つの値が必要です。iCustomなどで他のインジケーターから取得するような関数の場合、バッファのインデックスを指定して値を戻すようになっていますが、呼び出しのたびに計算していると思うと速度面で不安が残ります。

Build600以降のMQL4では構造体が使用できます。
関数の戻り値として構造体を使用すると二つ以上の値を一度に戻すことができます。
これを利用することで同じ計算から求められる値をまとめて取得することが可能です。

// メイン・シグナル構造体
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;
//今回は省略
return value;
}


二つ以上の値を戻す方法は、これ以外にも関数の引数を実体渡し(&をつけて宣言するやつです)する方法もありますが、引数に値がかえってくるよりも戻り値でかえってくる方が関数としての形が統一されて私はこちらをよく使います。

MQL4には指定配列のストキャスを求めるiStochasticOnArrayが見当たりませんでした。以前作成した「ストキャスティクスRSI オシレーターを作成してみた。」からストキャスを算出している部分を抽出して関数化しています。次回の記事では、こちらを紹介したいと思います。



2015年5月4日月曜日

MT4プログラムの小ネタ EU夏時間を判定するプログラム と雑談

前回、アメリカ夏時間を判定したので、今回はEU夏時間です。
こちらはイギリス夏時間がベースになっているようですので、それを判定したいと思います。

最終日曜日から最終日曜日までですので、EUの方が判定プログラムは簡単です。
月の最終日から、その日のTimeDayOfWeekで取得した値(日曜日0〜土曜日6)を引けば最終日曜日です。

//------------------------------------------------------------------
// 指定日時がEUサマータイムかどうか
// return 指定GMT時間がサマータイムの場合 true
bool IsEnglandSummerTime(
datetime gmt         // GMT
)
{
datetime londonTime = gmt;

MqlDateTime dt;
TimeToStruct(londonTime, dt);

//夏時間判定
datetime startSummerTime;
datetime endSummerTime;
MqlDateTime work;
int week;

// 標準時ベースで3月最終日曜日 AM1:00 ~ 10月最終日曜日AM1:00
work.year = dt.year;
work.mon = 3;
work.day = EndOfMonth(work.year, work.mon);;
work.hour = 1;
work.min = 0 ;
work.sec = 0 ;
week = TimeDayOfWeek(StructToTime(work));
work.day = work.day - week;

startSummerTime = StructToTime(work) ;

work.mon = 10;
work.day = EndOfMonth(work.year, work.mon);
work.hour = 1;
work.min = 0 ;
work.sec = 0 ;
week = TimeDayOfWeek(StructToTime(work));
work.day = work.day - week;

endSummerTime = StructToTime(work) ;

return startSummerTime <= londonTime && londonTime < endSummerTime;
}


GW中の日本時間は当たり前ですが、動きませんよね。値動きが少ない上に何かあると恐ろしい程動きます。テクニカル的には厳しい時間帯です。こんな時は取引せずに眺めているのが大切と考えています。現在作成しているEAではアメリカ・イギリス・日本の祝日フィルタを作成して各市場祝日の際は、取引しないようにしています。バックテストの結果にも影響をあたえるため10年分ぐらいは正しく判定出来るようにしましたが・・・テストがアホほど面倒でした。うーん。10年分のカレンダーデータをそのまま入れても良かったかなぁと作った後に少々後悔するほど手間がかかってしまいました。