2015年9月25日金曜日

[MT4プログラミング]二つの指標間に雲を描く

コメントにて雲を描いてはどうですか?というご意見があって、そもそもチャートに曇ってどうやって描くの?っていうところからスタートです^^;;

cloud.PNG

やり方はいくつかあると思うのですが、ここではヒストグラムを使った雲の描画をまず行いたいと思います。

サブウィンドウ上でのヒストグラムは、0を起点として描かれますが、チャート上では少し特殊な仕様となります。
まず、二つのバッファがセットになります。#property定義では奇数-偶数というセットになります。
例えばこんな感じです。
#property indicator_label1  "UP"
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  clrAqua
#property indicator_style1  STYLE_DOT
#property indicator_width1  1

#property indicator_label2  "DOWN"
#property indicator_type2   DRAW_HISTOGRAM
#property indicator_color2  clrIndianRed
#property indicator_style2  STYLE_DOT
#property indicator_width2  1


実際のバッファ指定ではバッファインデックス偶数-奇数のセットとなります。
int OnInit()
{
// ヒストグラムを描画する場合二つのバッファがセットになる。
// 必ず、偶数-奇数のペアにする。
// up[i] > down[i]の場合、バッファ0側の色(clrAqua)が使われ 
// down[i] > up[i]の場合、バッファ1側の色(clrIndianRed)が使われる
SetIndexBuffer(0,up);
SetIndexBuffer(1,down);


このとき、描画されるスタイルやカラーは値が大きいほうが採用されます。
上記例の場合
up[i] > down[i]の時はindicator_color1で指定されているclrAquaが、
up[i] < down[i]の時はindicator_color2で指定されているclrIndianRedが使用されます。
up[i] == down[i]の時には描画されません。

ということで、試しに二つの移動平均間をヒストグラムで結ぶプログラムを書いてみました。雲の形は階層状になっていたほうがそれっぽいなぁと思い、上位時間足の移動平均をもとに描画するようになっています。


FX-ONブログランキングにご協力よろしくお願いいたしますm(_ _ )m

//------------------------------------------------------------------
// 二つの移動平均の間をヒストグラムで結ぶ
#property copyright "Copyright 2015,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict
#property indicator_chart_window

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

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

#property indicator_label1  "UP"
#property indicator_type1   DRAW_HISTOGRAM
#property indicator_color1  clrAqua
#property indicator_style1  STYLE_DOT
#property indicator_width1  1

#property indicator_label2  "DOWN"
#property indicator_type2   DRAW_HISTOGRAM
#property indicator_color2  clrIndianRed
#property indicator_style2  STYLE_DOT
#property indicator_width2  1

#property indicator_label3  "MA1"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrRed
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1

#property indicator_label4  "MA2"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrYellow
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1

// 対象タイムフレーム
extern ENUM_TIMEFRAMES TargetPeriod = PERIOD_H4;

// 入力パラメータ 移動平均1期間
extern int Ma1Period = 11;

//入力パラメータ 移動平均1種別
extern ENUM_MA_METHOD Ma1Method = MODE_EMA;

// 入力パラメータ 移動平均2期間
extern int Ma2Period = 48;

//入力パラメータ 移動平均2種別
extern ENUM_MA_METHOD Ma2Method = MODE_EMA;

//入力パラメータ 表示移動
extern int   MaShift = 0;

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

//バッファー
double up[];
double down[];
double ma1[];
double ma2[];

//------------------------------------------------------------------
//初期化
int OnInit()
{
// ヒストグラムを描画する場合二つのバッファがセットになる。
// 必ず、偶数-奇数のペアにする。
// up[i] > down[i]の場合、バッファ0側の色(clrAqua)が使われ 
// down[i] > up[i]の場合、バッファ1側の色(clrIndianRed)が使われる
SetIndexBuffer(0,up);
SetIndexBuffer(1,down);

SetIndexBuffer(2,ma1);
SetIndexBuffer(3,ma2);

int maxPeriod = (int)MathMax(Ma1Period, Ma2Period);

SetIndexDrawBegin(0, maxPeriod);
SetIndexDrawBegin(1, maxPeriod);
SetIndexDrawBegin(2, maxPeriod);
SetIndexDrawBegin(3, maxPeriod);

string short_name = "cloud";
IndicatorShortName(short_name);

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[])            //スプレット
{
if( Period() > TargetPeriod ) return rates_total ;

for( int i = (rates_total - prev_calculated - 1); i >= 0 && !IsStopped(); i-- )
{
int shift = iBarShift(NULL, TargetPeriod, time[i], false);

ma1[i] = iMA(NULL, TargetPeriod, Ma1Period, MaShift, Ma1Method, MaPrice, shift);
ma2[i] = iMA(NULL, TargetPeriod, Ma2Period, MaShift, Ma2Method, MaPrice, shift);

//ma1 > ma2の場合clrAqua ma1 < ma2の場合はclrIndianRed
up[i] = ma1[i];
down[i] = ma2[i];
}
//元となる値を計算する。
return(rates_total - 1);
}





2015年9月24日木曜日

9/23のチャートとアップデートのお知らせ 周期解析内 CycleCancelEMAのアラート機能追加について

■2015/09/23 EURUSD 15分足 周期解析とCycleCancelEMA
Cycle20150923.PNG

ここ最近周期解析は15分足で見ています。
15分足だと周期解析のクロスがそれなりに発生します。
1時間より長いスパンだと価格の振動成分がバーの中に隠れてしまい、現在リリースしている周期解析ではクロスがあまり発生しません。
逆にCycleCancelEMAはあまり短い足で見てしまうとキャンセルしきれず、クロスが多発することになります。こちらは1時間足で見るとちょうどよい感じでデフォルトのパラメータを調整しています。

周期解析とCycleCancelEMAは同じ時間足ではなくて、周期解析を短い足、CycleCancleEMAをそれより長い足に適用すると見やすくなりますので、よろしければご確認ください。

FX-ON様で好評発売中(?)の周期解析ですが、CycleCancelEMAにアラート機能を付けてほしいとのご要望がありましたので、対応いたします。

ただいまテスト中ですので、しばらくお待ちください。
アップデートに従い下記設定を追加しました。
// 確定値がクロスした時アラートを発生する場合true
extern bool IsCloseCrossAlert = false;
// 現在値がクロスした時アラートを発生する場合true
extern bool IsCurrentCrossAlert = false;

//条件に一致した場合、サウンドを鳴らす。
extern bool IsAlertSound = true;
//再生サウンド名
extern string SoundFileName = "alert.wav";

//条件に一致した場合、メールを送信する。
extern bool IsAlertMail = true;


IsCurrentCrossAlertをtrueにした場合、その後価格が動いて実際にはクロスとならない場合がございますのでご注意ください。

メールを送信する場合はMT4の設定が必要です。
メニュー→ツール→オプション→E-メールタグ
■SMTPサーバー設定
EmailSettings.PNG
各入力項目は、ご使用されているプロパイダ様にお問い合わせください。

価格の行き過ぎ、トレンド、周期を確認して相場を制するセット
予測移動平均ボリンジャーバンド、トレンド強度相関、周期分析セット
予測移動平均ボリンジャーバンド、トレンド強度相関、周期分析セット | fx-on.com

2015年9月20日日曜日

[MT4インジケータ&プログラミング]状況に応じて色が変わるボリンジャーバンドで音を鳴らしてメールを送る。

上位時間足を表示するカラフルなボリンジャーバンドをさらに改造して、アラート音とメールを出せるようにします。

まずアラート音を鳴らすにはPlaySound関数を使用します。
PlaySound関数は引数は一つだけでファイル名を指定します。
bool PlaySound(
string filename //ファイル名
);

ここでのファイル名は、MT4インストールフォルダ内のSoundsフォルダのWAVファイルを指定可能です。
もし自分でオリジナルアラート音を追加したい場合はWAVファイルにして、このフォルダに入れる必要があります。WAVファイルの作成ツールはたくさんありますので、そちらを利用します。あまり再生時間が長すぎるととても大きなファイルになるため注意です。

■MT4 Soundsフォルダ
Sounds.PNG
初期ファイルとして、すでにいくつかファイルがあります。alert.wavを鳴らす場合は
PlaySound("alerf.wav");
と指定します。
ちなみに再生中の音を止めるには PlaySound(NULL);と指定するようです。


メールの送信はSendMail関数で行います。
bool SendMail(
string subject, // メールタイトル
string some_text // メール本文
);

この関数は送信先アドレスなどの設定は行えません。
MT4で設定できるため、そちらで設定しておく必要があります。
MT4のメニューからツール→オプションでオプション画面を開き
E-メールタブで編集します。

■E-メール設定
EmailSettings.PNG

各項目は、使用しているプロパイダから取得できますので、プロパイダの設定手順書などを参考にしてみてください。
Gmailとかも使える様子。なんだか使えないっていう記事も見かけますが。海外のほうではつながったーという記事も多々あるため、古いMT4の問題なんだろうなーと。現状でもつながらない場合は、たぶんGmailのAPPPINとかの問題ではないかなーとか。もし問題になっている人がいるようなら、今度調べて手順を記事にしてみようかな。ローカルにSMTPサーバー立てて中継させるとか面倒なことはせずとも対応可能なはず。

さておき、メールの設定が終わってテストが通っている前提で下記のインジケータを作成しました。

表示中チャートの終値が、表示中時間足ボリンジャーバンドの?σを超えた場合、音を鳴らしてメールを送信するプログラムです。

それぞれ、IsAlertMailとIsAlertSoundをFalseにすることで、機能を停止することができるようにしておきました。
FX-ONにも無料インジケータとして登録しましたので、コンパイルが面倒な方はそちらからダウンロードしてみてください。

余談)
お盆明けにPCが壊れたため、SkylakeなWindows10 PCに入れ替えました。
MT4は問題なく動作しております。
CPU使用率は相変わらず低い感じです。最近CPUとか、もうどうでもいい感じですよね^^;;;CPUパワー不足で困ったことがほとんどない・・。そして、やっぱりSSDサイコー!w


FX-ONブログランキングにご協力よろしくお願いいたしますm(_ _ )m

//------------------------------------------------------------------
// 色が変わるボリンジャーバンド 上位時間足版 アラート機能付き
#property copyright "Copyright 2015,  Daisuke"
#property link      "http://mt4program.blogspot.jp/"
#property version   "1.00"
#property strict
#property indicator_chart_window

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

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

#property indicator_label1  "CenterUp"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrAqua
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

#property indicator_label2  "HIGH1UP"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrSlateBlue
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1

#property indicator_label3  "HIGH2UP"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrSlateBlue
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1

#property indicator_label4  "LOW1UP"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrSlateBlue
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1

#property indicator_label5  "LOW2UP"
#property indicator_type5   DRAW_LINE
#property indicator_color5  clrSlateBlue
#property indicator_style5  STYLE_SOLID
#property indicator_width5  1

#property indicator_label6  "CenterDown"
#property indicator_type6   DRAW_LINE
#property indicator_color6  clrIndianRed
#property indicator_style6  STYLE_SOLID
#property indicator_width6  1

#property indicator_label7  "HIGH1DOWN"
#property indicator_type7   DRAW_LINE
#property indicator_color7  clrWheat
#property indicator_style7  STYLE_SOLID
#property indicator_width7  1

#property indicator_label8  "HIGH2DOWN"
#property indicator_type8   DRAW_LINE
#property indicator_color8  clrWheat
#property indicator_style8  STYLE_SOLID
#property indicator_width8  1

#property indicator_label9  "LOW1DOWN"
#property indicator_type9   DRAW_LINE
#property indicator_color9  clrWheat
#property indicator_style9  STYLE_SOLID
#property indicator_width9  1

#property indicator_label10  "LOW2DOWN"
#property indicator_type10   DRAW_LINE
#property indicator_color10  clrWheat
#property indicator_style10  STYLE_SOLID
#property indicator_width10  1

// 対象タイムフレーム
extern ENUM_TIMEFRAMES TargetPeriod = PERIOD_H4;

// 入力パラメータ 移動平均期間
extern int MaPeriod = 21;

//入力パラメータ 表示移動
extern int   MaShift = 0;

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

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

//標準偏差期間
extern int StdPeriod = 21;

//標準偏差算出方法
extern ENUM_MA_METHOD StdMethod = MODE_SMA;

//σ1
extern double Sigma1 = 1;

//σ2
extern double Sigma2 = 2;

//条件に一致した場合、サウンドを鳴らす。
extern bool IsAlertSound = true;
//再生サウンド名
extern string SoundFileName = "alert.wav";

//条件に一致した場合、メールを送信する。
extern bool IsAlertMail = true;

//終値が次シグマを超えた場合アラートを鳴らす
extern double AlertSigma = 1;


double centerUp[];
double high1Up[];
double high2Up[];
double low1Up[];
double low2Up[];

double centerDown[];
double high1Down[];
double high2Down[];
double low1Down[];
double low2Down[];

//------------------------------------------------------------------
//初期化
int OnInit()
{
//インジケーターバッファを初期化する。
SetIndexBuffer(0,centerUp);
SetIndexBuffer(1,high1Up);
SetIndexBuffer(2,high2Up);
SetIndexBuffer(3,low1Up);
SetIndexBuffer(4,low2Up);
SetIndexBuffer(5,centerDown);
SetIndexBuffer(6,high1Down);
SetIndexBuffer(7,high2Down);
SetIndexBuffer(8,low1Down);
SetIndexBuffer(9,low2Down);
SetIndexDrawBegin(0, MaPeriod);
SetIndexDrawBegin(1, MaPeriod);
SetIndexDrawBegin(2, MaPeriod);
SetIndexDrawBegin(3, MaPeriod);
SetIndexDrawBegin(4, MaPeriod);
SetIndexDrawBegin(5, MaPeriod);
SetIndexDrawBegin(6, MaPeriod);
SetIndexDrawBegin(7, MaPeriod);
SetIndexDrawBegin(8, MaPeriod);
SetIndexDrawBegin(9, MaPeriod);

string short_name = "ClBB(" + IntegerToString(MaPeriod) + ")";
IndicatorShortName(short_name);

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[])            //スプレット
{
if( Period() > TargetPeriod ) return rates_total ;

for( int i = (rates_total - prev_calculated - 1); i >= 0 && !IsStopped(); i-- )
{
if( i >= rates_total - 2 ) continue;

int shift1 = iBarShift(NULL, TargetPeriod, time[i], false);
int shift2 = iBarShift(NULL, TargetPeriod, time[i + 1], false);

double ma1 = iMA(NULL, TargetPeriod, MaPeriod, 0, MaMethod, MaPrice, shift1);
double ma2 = iMA(NULL, TargetPeriod, MaPeriod, 0, MaMethod, MaPrice, shift1 + 1);

//ひとつ前の値は、表示している時間足の切り替えが発生したかどうかで変わる。
double minus1Center = shift1 == shift2 ? ma1 : ma2;

// 移動平均の方向によって値を設定するバッファーを変更する。
if( ma1 < ma2 )
{
centerDown[i] = ma1;
centerDown[i + 1] = minus1Center;
}
else
{
centerUp[i] = ma1;
centerUp[i + 1] =  minus1Center;
}

double std1 = iStdDev(NULL, TargetPeriod, StdPeriod, 0, StdMethod, MaPrice, shift1);
double std2 = iStdDev(NULL, TargetPeriod, StdPeriod, 0, StdMethod, MaPrice, shift1 + 1);

//ひとつ前の値は、表示している時間足の切り替えが発生したかどうかで変わる。
double minus1Std = shift1 == shift2 ? std1 : std2;


// 標準偏差の大きさによって値を入れるバッファを切り替える。
if( std1 < std2 )
{
high1Down[i] = ma1 + std1 * Sigma1;
high2Down[i] = ma1 + std1 * Sigma2;

low1Down[i] = ma1 - std1 * Sigma1;
low2Down[i] = ma1 - std1 * Sigma2;

high1Down[i + 1] = minus1Center + minus1Std * Sigma1;
high2Down[i + 1] = minus1Center + minus1Std * Sigma2;

low1Down[i + 1] = minus1Center - minus1Std * Sigma1;
low2Down[i + 1] = minus1Center - minus1Std * Sigma2;
}
else
{
high1Up[i] = ma1 + std1 * Sigma1;
high2Up[i] = ma1 + std1 * Sigma2;

low1Up[i] = ma1 - std1 * Sigma1;
low2Up[i] = ma1 - std1 * Sigma2;

high1Up[i + 1] = minus1Center + minus1Std * Sigma1;
high2Up[i + 1] = minus1Center + minus1Std * Sigma2;

low1Up[i + 1] = minus1Center - minus1Std * Sigma1;
low2Up[i + 1] = minus1Center - minus1Std * Sigma2;
}

// 最終アラート発生時刻
static datetime lastAlertTime = 0;
// 前回がアラートシグマ未満で、今回がアラートシグマ以上なら音をならしてメールを送信する。
// 過去データの計算でアラートが発生するのを防止するため、iが1の時のみ。
if( i == 1 && (IsAlertMail || IsAlertSound ) && lastAlertTime != time[i] )
{
double alertStd1 = std1 * AlertSigma;
double alertStd2 = minus1Std * AlertSigma;

if( (close[i + 1] < (minus1Center + alertStd2) && close[i] >= (ma1 + alertStd1))
|| (close[i + 1] > (minus1Center - alertStd2) && close[i] <= (ma1 - alertStd1)))
{
if( IsAlertSound )
{
PlaySound(SoundFileName);
}

if( IsAlertMail )
{
//タイトル
string subject = StringFormat("ColorfulMTBB アラート %s[%d] %s", Symbol(), Period(), TimeToStr(time[i]) );

//本文
string message = "ColorfulMTBBの設定によりアラートメールを送信しました。\r\n";
StringAdd(message, StringFormat("MA:%f\r\n", ma1));
StringAdd(message, StringFormat("LowerStd:%f\r\n", ma1 - alertStd1));
StringAdd(message, StringFormat("UpperStd:%f\r\n", ma1 + alertStd1));
StringAdd(message, StringFormat("Close:%f\r\n", close[i]));
SendMail(subject, message);
}

lastAlertTime = time[i];
}
}

}
return(rates_total - 1);
}