【小ネタ】MT4用T/P、S/L設定スクリプト
私が使い方知らないだけですかね(;´д`)
探せば同じようなスクリプトがあるのかもしれませんが、
勉強も兼ねて設定ツールを作ってみました。
TPSLUTY.zip(ソース付き)
ダウンロードしたTPSLUTY.zipを解凍し、MT4のexperts\scriptsフォルダに放り込みます。
MT4を起動するとコピー場所が間違ってなければScriptsの中に4つのスクリプトがあるはずです。

MT4メニューの「ツール-オプション-Expert Adviser」でスクリプトからオーダーの変更ができるように設定します。

変更したいオーダーの建値近くにYP_1MODIFY_TPSLをドラッグしてドロップします。

価格ラベルオブジェクトが生成されます。

水色がリミット用、黄色がストップ用の価格ラベルです。
すでにT/P、S/Lが設定されている場合は、その位置に表示されます。
未設定の場合はT/Pが20pips、S/Lが30pipsの位置に表示されます。
デフォルトpips数はソースで#defineしているので適当に変更してください。
移動したい価格ラベルをダブルクリックして選択しドラッグで移動します。

YP_2MODIFY_ENDをダブルクリックしてオーダーします。
T/P、S/L設定を中止する場合は、YP_3MODIFY_CANCELをダブルクリックします。


YP_DELETE_TPSLはT/P、S/L設定を削除する場合に使用します。
YP_1MODIFY_TPSLと同じように削除したいオーダーの建値近くにドロップします。
お役に立てば良いんだけど(´・ω・)

【小ネタ】MT4アラートが表示されている間、音を鳴らすインジケータ
気付かない時がありますよね?
で、アラートダイアログが表示されている間、
音を鳴らすインジケータです。
単純にアラートダイアログが表示されているかどうかだけで
判断しているので、いくつもMT4を起動している場合、
どのアラートダイアログにも反応します。
// AlertAlert.mq4
#include <WinUser32.mqh>
#property indicator_chart_window
extern string WindowClass = "#32770";
extern string WindowCaption = "警告";
extern string SoundFile = "expert.wav";
int init(){return(0);}
int deinit(){return(0);}
int start()
{
int counted_bars=IndicatorCounted();
if(Bars == counted_bars + 1){
int hWnd = FindWindowA(WindowClass, WindowCaption);
if(hWnd != 0)
if(IsWindowVisible(hWnd) != 0)
PlaySound(SoundFile);
}
return(0);
}
こちらは動作確認用のインジです。
// AlertAlertTest.mq4
#property indicator_chart_window
int init()
{
Alert("AlertAlert test");
return(0);
}
int deinit(){return(0);}
int start(){return(0);}
MeteEditorはメニューのTools-Options-FontsでScriptを日本語にして
FontをMSゴシック等にしないと日本語が文字化けします。

たまにはEA作成講座でも・・・その3
メール送信関数SendOrderMail()を解説したいと思います。
またまたコードにバグがありました。m(__)m
void SendOrderMail(int ticket, bool bOpen)
{
.
.
.
body = body + "Price:" + DoubleToStr(OrderClosePrice(), MarketInfo(OrderSymbol(),MODE_DIGITS)) + "\r\n";
if(!bOpen){
body = body + "Swap:" + DoubleToStr(OrderSwap(), MarketInfo(OrderSymbol(),MODE_DIGITS)) + "\r\n";
body = body + "Profit:" + DoubleToStr(OrderProfit(), MarketInfo(OrderSymbol(),MODE_DIGITS)) + "\r\n";
}
.
.
.
}
の部分ですが、
void SendOrderMail(int ticket, bool bOpen)
{
.
.
.
if(bOpen){
body = body + "Price:" + DoubleToStr(OrderOpenPrice(), MarketInfo(OrderSymbol(),MODE_DIGITS)) + "\r\n";
}else{
body = body + "Price:" + DoubleToStr(OrderClosePrice(), MarketInfo(OrderSymbol(),MODE_DIGITS)) + "\r\n";
body = body + "Swap:" + DoubleToStr(OrderSwap(), MarketInfo(OrderSymbol(),MODE_DIGITS)) + "\r\n";
body = body + "Profit:" + DoubleToStr(OrderProfit(), MarketInfo(OrderSymbol(),MODE_DIGITS)) + "\r\n";
}
.
.
.
}
と、しないと建値が正しく取得できませんね。
---------------------------------------------------------------------
以下、SendOrderMail()の解説です。
まず関数の宣言、void SendOrderMail(int ticket, bool bOpen)ですが、
voidキーワードは、この関数が値を返さないという意味です。
例えばstart()関数にはintが付いているので整数型を返しますよという意味になります。
SendOrderMailは関数名でticket、bOpenは仮引数でそれぞれint(整数型)、
bool(論理型)です。
この関数を呼び出すとき、例えばSendOrderMail(123, false)と記述すれば、
SendOrderMail()関数内でticket、bOpenを参照したとき、それぞれの値は123、falseとなります。
メールを送信するときに、オーダーのチケット番号から、
オーダー時刻、建値、決済値、利益等の情報を取得する目的で、
呼び出し側からticketにチケット番号を渡しています。
bOpenにはオープン時のメール(true)なのかクローズ時のメール(false)なのかを
渡しています。
int modeについてですが、OrderSelect()関数の第3引数で、
現在ポジション(MODE_TRADES)からオーダーを取得するのか
決済キャンセル済み(MODE_HISTORY)からオーダーを取得するのか
を渡す必要がありますが、その値を格納する目的の整数型変数の宣言です。
string subjectは、メールの件名を格納する文字列型変数の宣言です。
if(bOpen){でオープン時のメールなのか、決済時のメールなのかを判断しています。
オープン時のメールの時は、bOpenはtrueで呼ばれるので、
mode = MODE_TRADESで現在ポジションからオーダーを取得、
subject =OrderOpenMailSubjectでメール件名は、OrderOpenMailSubjectプロパティ値を
使用するという事になります。
bOpenがfalseの場合は、mode = MODE_HISTORYでオーダー取得は履歴から、
subject =OrderCloseMailSubjectでメール件名は、OrderCloseMailSubjectプロパティ値を
採用することになります。
続く・・・・。

たまにはEA作成講座でも・・・その2
前回、最後に掲載したソースですが、冒頭部分のEAプロパティの解説が抜けていました。
//---- input parameters
extern bool OrderOpenMail=true;
extern string OrderOpenMailSubject="Order Open Mail";
extern bool OrderCloseMail=true;
extern string OrderCloseMailSubject="Order Close Mail";
の部分ですが、この記述によりEAのプロパティ画面が次の様になります。

externキーワードは外部から参照されるという意味で、
EAのプロパティ値としてユーザが変更できる変数を宣言する時に使います。
boolは変数の型でtrue(真)またはfalse(偽)のどちらかの値を持ちます。
OrderOpenMail=true;とすることで変数OrderOpenMailの初期値はtrueにするという意味になります。
OrderOpenMail変数は、新たにポジションを持ったときにメール送信を行うかどうかを
ユーザが指定出来る様にしようと考えたからです。
と思って前回のソースをよく見るとこの変数が効いていなかった。_| ̄|○
int start()
{
.
.
.
for(i = 0; i < NUM_POSITION_SIZE; i++){
if(!LiveMap[i] && aiTicket[i] != 0){
//closed order
SendOrderMail(aiTicket[i], false);
aiTicket[i] = 0;
}
}
.
.
.
if(!bFound){
//new order found
SendOrderMail(ticket, true);
for(i = 0; i < NUM_POSITION_SIZE; i++){
if(aiTicket[i] == 0){
aiTicket[i] = ticket;
break;
}
}
}
.
.
.
}
の部分ですが、
int start()
{
.
.
.
for(i = 0; i < NUM_POSITION_SIZE; i++){
if(!LiveMap[i] && aiTicket[i] != 0){
//closed order
if(OrderCloseMail)
SendOrderMail(aiTicket[i], false);
aiTicket[i] = 0;
}
}
.
.
.
if(!bFound){
//new order found
if(OrderOpenMail)
SendOrderMail(ticket, true);
for(i = 0; i < NUM_POSITION_SIZE; i++){
if(aiTicket[i] == 0){
aiTicket[i] = ticket;
break;
}
}
}
.
.
.
}
とする必要がありますね。
EAのプロパティ値の話に戻りますが、stringというのは文字列型変数の宣言で、
OrderOpenMailSubject="Order Open Mail";で新たにポジションを持ったときの
メールの「件名」をユーザが変更できる様にしています。
OrderCloseMail、OrderCloseMailSubjectについては
同様にポジションをクローズしたときのメールに関するプロパティです。
たまにはEA作成講座でも・・・その3に続く。

たまにはEA作成講座でも・・・その1
といってもテクニカルにはからきし疎いので、ヾ(--;)
ポジションを持ったときやクローズしたときにメールを送るEAを作りたいと思います。
メール送信機能のないEAといっしょに使うといいかも。
ではでは、MetaTraderの前に集合ーっ!
まず、MT4を起動しメニューの「ツール」-「MetaQuotes language Editor」を起動します。

MeteEditorが起動したらメニューの「File」-「New」を選択します。

Expert Advisor Wizardが起動するのでExpert Advisorを選んで次へをクリックします。

Name(EA名)にSendMailと入力し完了をクリックします。

するとEAのテンプレートができましたよね?
//+------------------------------------------------------------------+
//| SendMail.mq4 |
//| Copyright ゥ 2011, MetaQuotes Software Corp. |
//| http://www.metaquotes.net |
//+------------------------------------------------------------------+
#property copyright "Copyright ゥ 2011, MetaQuotes Software Corp."
#property link "http://www.metaquotes.net"
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
//----
//----
return(0);
}
//+------------------------------------------------------------------+
//~行末まではコメントでプログラムには影響しません。
#propertyの行もプログラムの動作とは関係ないので無視して良いです。
以下の3つの関数が出来ています。
init()・・・EAの初期化タイミングで一度だけMT4から呼ばれます。
deinit()・・・EAの終了タイミングで一度だけMT4から呼ばれます。
start()・・・ティック毎(価格変動時)に毎回MT4から呼ばれます。
※「呼ばれます」と書きましたが、EAはMT4から呼ばれない限り、自ら能動的には動作することができません。
さて、これからプログラムを記述するわけですが、まず方針を決めます。
目的のメールを送信するためにはポジションが変化したかどうかを判断する必要があります。
方法は色々あると思いますが、今回はinit()関数で現在ポジションを変数に保存しておき、
start()関数で毎回ポジションに変化があったかどうかで判断しようと思います。
init()関数の前に現在ポジションのチケット番号を記憶する領域を宣言します。
#define NUM_POSITION_SIZE 32
int aiTicket[NUM_POSITION_SIZE];
#defineは記号常数で「プログラム中でNUM_POSITION_SIZEと書いたら32に置き換えてね」と言う意味です。
intは変数の型で整数という意味、aiTicketは配列変数の名前、[NUM_POSITION_SIZE]で、
この配列変数には32個の整数が記憶できるという意味になります。
32というのは私が勝手に決めた数で、このくらいで十分かなと思っただけです。
init()関数に現在ポジションを収集するコードを書き加えます。
int init()
{
int i, cnt;
int total = OrdersTotal();
for(i = 0; i < NUM_POSITION_SIZE; i++)
aiTicket[i] = 0;
for(i = 0, cnt = total - 1; i < NUM_POSITION_SIZE && cnt >= 0 ; cnt--){
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if(OrderType() == OP_BUY || OrderType() == OP_SELL){
aiTicket[i] = OrderTicket();
i++;
}
}
return(0);
}
int i, cnt;はinit()関数の中で使う変数の宣言です。
int total = OrdersTotal();では変数totalに現在の全オーダー数を取得しています。
この様に変数は宣言と同時に値を割り当てることもできます。OrdersTotal()はMQL4で提供されている関数です。
どの様な関数があるかはこちらが参考になると思います。
※上記がリンク切れの場合メタトレーダー4日本語リファレンス「メタシス・シーカー【MetaSys-Seeker.net】」
上部の「MQL言語リファレンス」を辿ってください。
for(i = 0; i < NUM_POSITION_SIZE; i++)は繰り返し処理で、変数iの値を0~NUM_POSITION_SIZE-1まで
1ずつ増やしながら次の行aiTicket[i] = 0;を実行します。
つまりaiTicket[0]~aiTicket[31]に0がセットされます。
※配列の添え字は0から始るので、配列のサイズ-1が添え字の上限になります。
チケット番号は0以外なのでaiTicket配列の要素が0なら、そこは空き要素と判断できます。
for(i = 0, cnt = total - 1; i < NUM_POSITION_SIZE && cnt >= 0 ; cnt--){ですが、
上のfor文よりちょっとだけ複雑です。
for文はセミコロンで3つの部分に分けられますが、最初のパートが変数の初期化で、
この場合はiに0を代入し、cntにtotal - 1を代入しています。カンマで区切っていくらでも
書くことが出来ます。初期化が不要なら何も書かずに;だけでも良いという柔軟な仕様です。
極端な話for(;;)でも文法的には通ります。このままでは脱出できませんが・・・。
次のパートは繰り返し処理の継続条件でここに書いた条件が満たされている間、
{~}までが実行されます。さっきのfor文では{}が付いていませんが、
繰り返し実行する文が1行だけなら{}を付けなくてもいいです。
最後のパートが次の繰り返し処理に行く前に行う計算です。
で、話を戻してループの継続条件ですがi < NUM_POSITION_SIZE && cnt >= 0は、
iの値がNUM_POSITION_SIZEより小さく、なおかつcntの値が0以上なら継続という意味になります。
iはaiTicket配列の添え字に使っていて、iが配列のサイズを超えることが出来ないので
保険として書いています。
また、cntはオーダー数分繰り返すので、次のcnt--と合わせてtotal - 1~0までが取り得る値なります。
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);で「これからcnt番目のオーダーを参照しますよ」と
MT4に伝えています。
これからポジションを持っているオーダーを収集したいので
if(OrderType() == OP_BUY || OrderType() == OP_SELL){で判断します。
というのは、オーダーの中には指値待機オーダーや逆指値待機オーダーも含まれているため、
買ポジかまたは売ポジだけを抽出したいからです。
aiTicket[i] = OrderTicket();でi番目の配列要素(0から始まります)にチケット番号を
保存しています。
チケット番号の保存場所をi++;で次に進めます。
あーしんど。意外と大変なので完成ソースでお茶を濁して
残りの解説は次回(需要あるのか?)に続く・・・(爆
//+------------------------------------------------------------------+
//| SendMail.mq4 |
//| yuki |
//| http://paopao46.blog34.fc2.com/ |
//+------------------------------------------------------------------+
#property copyright "yuki"
#property link "http://paopao46.blog34.fc2.com/"
#define NUM_POSITION_SIZE 32
//---- input parameters
extern bool OrderOpenMail=true;
extern string OrderOpenMailSubject="Order Open Mail";
extern bool OrderCloseMail=true;
extern string OrderCloseMailSubject="Order Close Mail";
int aiTicket[NUM_POSITION_SIZE];
//+------------------------------------------------------------------+
//| expert initialization function |
//+------------------------------------------------------------------+
int init()
{
int i, cnt;
int total = OrdersTotal();
for(i = 0; i < NUM_POSITION_SIZE; i++)
aiTicket[i] = 0;
for(i = 0, cnt = total - 1; i < NUM_POSITION_SIZE && cnt >= 0 ; cnt--){
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
if(OrderType() == OP_BUY || OrderType() == OP_SELL){
aiTicket[i] = OrderTicket();
i++;
}
}
return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function |
//+------------------------------------------------------------------+
int deinit()
{
return(0);
}
//+------------------------------------------------------------------+
void SendOrderMail(int ticket, bool bOpen)
{
int mode;
string subject;
if(bOpen){
mode = MODE_TRADES;
subject =OrderOpenMailSubject;
}else{
mode = MODE_HISTORY;
subject =OrderCloseMailSubject;
}
if(OrderSelect(ticket, SELECT_BY_TICKET, mode)){
string body = "Time:";
datetime dt;
if(bOpen)
dt = OrderOpenTime();
else
dt = OrderCloseTime();
dt = dt + (TimeLocal() - TimeCurrent());
body = body + TimeToStr(dt,TIME_DATE|TIME_SECONDS) + "\r\n";
body = body + "Type:";
switch(OrderType()){
case OP_BUY:
case OP_BUYLIMIT:
case OP_BUYSTOP:
body = body + "buy\r\n";
break;
case OP_SELL:
case OP_SELLLIMIT:
case OP_SELLSTOP:
body = body + "sell\r\n";
break;
}
body = body + "Size:" + DoubleToStr(OrderLots(), 2) + "\r\n";
body = body + "Symbol:" + OrderSymbol() + "\r\n";
body = body + "Price:" + DoubleToStr(OrderClosePrice(), MarketInfo(OrderSymbol(),MODE_DIGITS)) + "\r\n";
if(!bOpen){
body = body + "Swap:" + DoubleToStr(OrderSwap(), MarketInfo(OrderSymbol(),MODE_DIGITS)) + "\r\n";
body = body + "Profit:" + DoubleToStr(OrderProfit(), MarketInfo(OrderSymbol(),MODE_DIGITS)) + "\r\n";
}
SendMail(subject, body);
Print("Mail Sent ", body);
}
}
//+------------------------------------------------------------------+
//| expert start function |
//+------------------------------------------------------------------+
int start()
{
static datetime dtLastTime = 0;
static string sLastCommandNo = "";
//check by 2 seconds
if(TimeLocal() - dtLastTime < 2)
return(0);
//save current time
dtLastTime = TimeLocal();
int i, cnt, ticket;
//check close
int total = OrdersTotal();
bool LiveMap[NUM_POSITION_SIZE];
for(i = 0; i < NUM_POSITION_SIZE; i++)
LiveMap[i] = false;
for(cnt = total - 1; cnt >= 0 ; cnt--){
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
ticket = OrderTicket();
if(OrderType() == OP_BUY || OrderType() == OP_SELL){
for(i = 0; i < NUM_POSITION_SIZE; i++){
if(aiTicket[i] == ticket){
LiveMap[i] = true;
break;
}
}
}
}
for(i = 0; i < NUM_POSITION_SIZE; i++){
if(!LiveMap[i] && aiTicket[i] != 0){
//closed order
SendOrderMail(aiTicket[i], false);
aiTicket[i] = 0;
}
}
//check open
bool bFound;
total = OrdersTotal();
for(cnt = total - 1; cnt >= 0 ; cnt--){
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
ticket = OrderTicket();
if(OrderType() == OP_BUY || OrderType() == OP_SELL){
bFound = false;
for(i = 0; i < NUM_POSITION_SIZE; i++){
if(aiTicket[i] == ticket){
bFound = true;
break;
}
}
if(!bFound){
//new order found
SendOrderMail(ticket, true);
for(i = 0; i < NUM_POSITION_SIZE; i++){
if(aiTicket[i] == 0){
aiTicket[i] = ticket;
break;
}
}
}
}
}
return(0);
}
//+------------------------------------------------------------------+
上のソースをMeteEditorにコピペして保存するとMT4で使える様になります(多分)。
MT4メニューの「ツール」-「オプション」-「E-メール」の設定もお忘れ無く!
たまにはEA作成講座でも・・・その2に続く。

| h o m e |