mt4 (MetaTrader4)使い倒シストレ

メタトレーダー、自作インジケータ、自作EAで完全自動売買。使えるものは何でも使え。
インジケーター、EA(自動売買システム)製作のご依頼はこちらへ
Googolyen FX Factory
スポンサーサイト
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。


にほんブログ村 為替ブログ FX システムトレード派へ
--/--/--(--) --:--:-- | スポンサー広告 | Trackback(-) | Comment(-)
Japanese Programing

MQL4はプログラミング言語Cとよく似ている言語です。
(自由度としてはあまり高くありませんが…(涙)

しかしながら、MQL4ではCには無い特別な機能(?)があります。

以下のコードをみてください。

#define π 3.14159286

//+------------------------------------------------------------------+
//| script program start function |
//+------------------------------------------------------------------+
int start()
{
double ラジアン = ラジアン変換(180.0);
double 度 = 度変換(3.14159286);
Comment(ラジアン, ", ", 度);

}

double ラジアン変換(double 度)
{
return (2.0*度*π/180.0);
}

double 度変換(double ラジアン)
{
return ((180.0*ラジアン)/(2.0*π));
}


普段MQL4を使っておられる方は、少し違和感を覚えるコードですね。
(MetaEditor上で上記コードをペーストしても文字化けを起こす場合は、
フォントをTerminalに変更してください。)

そう!

変数名や関数名に「日本語」を使っているのです。
そして上記のコードは、何事もなかったかのようにコンパイルできます。

もちろん「日本語」だけではなく、ロシア語、中国語、アラビア語(できるのだろうか)、etc...
枚挙に暇なく、様々な国の言葉でプログラミングができます。


なんという国際化言語。

この辺りに力を入れたMQL4の開発者は、
より多くの人にこの言語を使ってもらいたかったのではないでしょうか!
(言語としての自由度を抑えてでも…うぅ…(涙))


ちなみにオブジェクト指向プログラミング言語Javaでも国際化に対応してます。
って全然関係ないですね(笑)


日本語を使ったプログラミングの利点としては
・変数や関数名が非常に分かりやすくなる(だって日本語ですもの)。
・変数や関数名の命名に悩まない(だって日本語…(略))。
・いつもと違う雰囲気を楽しめる(だtt…(略))


逆に欠点としては
・プログラミング中に「半角/全角」キーを何度も押さなければならない。
・日本語1文字消すのに、「BackSpace」を2回押さなければならない。
・文字の消し忘れによって構文エラーが混入する可能性がある。
・表示フォントに依存する。


こんなところでしょうか。


上記の利点・欠点を踏まえて

エンジョイ MQL4プログラミング!!



にほんブログ村 為替ブログ FX システムトレード派へ
スポンサーサイト
staticを使って健康的に
MQL4では『static』を使用することができます。
このstatic、実はとても便利なものなんです
(便利、便利じゃないの基準は色々あると思いますが、
私は便利と思ってます(笑))。



まずはstaticの使い方について少々。

以下のコードを見てください。

int start()
{
int counter, counter_s;
counter = RunningTimes();
counter_s = RunningTimes_s();
Comment(counter, ", ", counter_s);
}

int RunningTimes()
{
int count = 0;
count++;
return (count);
}

int RunningTimes_s()
{
static int count = 0;
count++;
return (count);
}


このコードを実行すると、
・counterの値はずっと1のまま
・counter_sの値は1ずつ増加する

となります。
前回この関数を呼び出した時のcount値を覚えておいて、その値に1を足している訳です。
static変数を使えば、その関数を抜けた後も、値を保持することができるのです。


値を保持する為に『グローバル変数を使っていた場面』に使えるんです。

よく見かける場面を見てみましょう。

int AllBars;
bool isNewBar()
{
bool res=false;
if (AllBars!=Bars)
{
AllBars=Bars;
res=true;
}
return(res);
}

新足が登場するとtrueを返す関数です。

この関数内で使われているAllBars変数の特徴は以下です。
・AllBars変数はグローバル領域で宣言された変数
・AllBars変数はプログラム全体の中でisNewBar()関数内でしか使われない
・AllBarsは値を保持する為に使われている

ピコーン!


staticが使えます。
そしてstaticを使えば、グローバル変数の数を1個減らすことができますね。

isNewBar()関数をstaticを使って書き換えたコードが以下になります。

bool isNewBar()
{
static int allBars = 0;
bool res=false;
if (allBars!=Bars)
{
allBars=Bars;
res=true;
}
return(res);
}


たったこれだけですが、グローバル変数を減らすことに成功しました。
これで前回記事にした、グローバル変数乱用の弊害から一つ逃れることができますね。


健康的なソースファイル作りにお役立てください。

にほんブログ村 為替ブログ FX システムトレード派へ
Order関数使ってますか?
EAやScriptを自作される方は、Order関数群を使っておられるはずです。
for文内でポジションのクローズ処理を書くのが、一般的ではないでしょうか。

以下の2コードを見てください。


コードA

int start()
{
int i, magic;
magic = 111;
for (i = 0; i < OrdersTotal() - 1; i++) {
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false)
continue;
if (OrderSymbol() != Symbol() || OrderMagicNumber() != magic)
continue;

if (OrderType() == OP_BUY)
OrderClose(OrderTicket(), OrderLots(), Bid, 3);
else if (OrderType() == OP_SELL)
OrderClose(OrderTicket(), OrderLots(), Ask, 3);
}
}


コードB

int start()
{
int i, magic;
magic = 111;
for (i = OrdersTotal() - 1; i >= 0; i--) {
if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES) == false)
continue;
if (OrderSymbol() != Symbol() || OrderMagicNumber() != magic)
continue;

if (OrderType() == OP_BUY)
OrderClose(OrderTicket(), OrderLots(), Bid, 3);
else if (OrderType() == OP_SELL)
OrderClose(OrderTicket(), OrderLots(), Ask, 3);
}
}

2つのコードではfor (...)部分が違うだけです。
Aではiの値が1ずつ増加(インクリメント)しています。
Bではiの値が1ずつ減少(デクリメント)しています。

このコードは、
『複数ポジションを持っていた場合に、全てのポジションをクローズする』
という処理を行っているように見えます。

しかし、

実はコードAでは全てのポジションをクローズすることはできません


iがインクリメントしているか、デクリメントしているか
たったこれだけの違いで現われてくる問題なんです。




具体的に解説します。
今、3つのポジションを持っていると仮定しましょう。
3つのポジションにおける情報は以下の通りとします。





呼び名ポジション番号(iの値によって選択)チケット番号タイプ
ポジションa0100BUY
ポジションb1101SELL
ポジションc2102BUY



○コードB
まずi = 2(OrdersTotal() - 1)によってポジションcが選択され、ポジションcが決済されました。
決済された後のポジションの状態は以下になります。




呼び名ポジション番号(iの値によって選択)チケット番号タイプ
ポジションa0100BUY
ポジションb1101SELL

その後iはデクリメントされi = 1となります。

i = 1によってポジションbが選択され、…以下略


と、i = -1になるまで以上の操作が繰り返され、めでたく全クローズが完了します。


○続いてA
i = 0によってポジションaが選択され、ポジションaが決済されました。
決済された後のポジションの状態は以下になります。




呼び名ポジション番号(iの値によって選択)チケット番号タイプ
ポジションb0101SELL
ポジションc1102BUY

その後iはインクリメントされi = 1となります。

i = 1によってポジションbが…あれれ?
i = 1によって選択されるのはポジションcですね。
これでは最終的にポジションbが残ってしまうことになりますね。


ポジションが決済される度に、ポジション番号は再割り振りされるみたいで、
その影響でコードAでは全クローズが完了しないのです。





クローズ処理をしないのであれば、コードAでも問題ありませんが、
クローズ処理をする、しないに関わらず、コードBのように書いた方がいいと思います。




にほんブログ村 為替ブログ FX システムトレード派へ
参照渡しに関するご質問
参照渡しは、とても便利かも!記事内で
記載したコードについてご質問がありましたので、
今回の記事をもって回答という形にさせていただきます。

【ご質問内容】
例えば(1)void func(int &arg0){処理}
と(2)int func(int arg0){処理~return(arg0)}
この2つ結果は同じと思うのですが、どう使い分ければよいのでしょうか?


int func1(int arg0) {
arg0++;
return (arg0);
}

void func2(int &arg0) {
arg0++;
}

int start()
{
int hoge = 1;
int hogehoge = 1;

hoge = func1(hoge);

func2(hogehoge);

Comment("hoge = ", hoge, "\n",
"hogehoge = ", hogehoge);

//結果
//hoge = 2
//hogehoge = 2
}


結果を見て分かるように、使い方は異なるにしろ、二つの関数(func1とfunc2)は同じ動作をします。
違う点は

  • 変更した結果を返しているか
  • 参照渡しをして引数の値自体を変更しているか

の違いだけです。

今回のご質問は『返り値を返す関数と、参照渡しを使った関数の使い分け』ということでしたので
そこに主眼を置いてご説明したいと思います。
つまり、この記事にある『便利な使い方』を除いた場合の、参照渡しの有用性を主観的にご説明します(笑)。


まず結論から言うと

値を得ることが目的であれば、返り値を使い
値の変更が目的であれば、参照渡しを使う


だと思います。

例えば、『MACDとRSIの状態からシグナルを発生させる関数』を作るとしましょう。

そこで二つの関数を書いてみました。
一方はシグナルを返り値として返す関数(MacdRsiSignal関数)、
もう一方はシグナルを参照渡しによって変更させる関数(MacdRsiSignal2関数


#define SELL_SIGNAL -1
#define BUY_SIGNAL 1
#define NO_SIGNAL 0

int MacdRsiSignal(double macd, double rsi)
{
//ふにゃふにゃ処理
//

if (BUY条件)
return (BUY_SIGNAL);
else if (SELL条件)
return (SELL_SIGNAL);
else
return (NO_SIGNAL);
}

void MacdRsiSignal2(int &signal, double macd, double rsi)
{
//ふにゃふにゃ処理
//

if (BUY条件)
signal = BUY_SIGNAL;
else if (SELL条件)
signal = SELL_SIGNAL;
else
signal = NO_SIGNAL;
}

int start()
{
double macd = iMACD(/*省略*/);
double rsi = iRSI(/*省略*/);
int signal1, signal2;

// 返り値によってシグナルを得る
signal = MacdRsiSignal(macd, rsi);

// 参照渡しによってシグナルを変更する
MacdRsiSignal2(signal2, macd, rsi);
}



この二つの関数を見て
『MACDとRSIの状態からシグナルを発生させる関数』
を作ろうとした場合、どちらが感覚的にしっくり来るでしょうか?

私としましては、MacdRsiSignal関数の方がしっくりします。
それは
今回作ろうとしている関数を、参照渡しによって値を変更するという方法によって実装してしまうと、シグナル発生という目的に合わない
からです。


では次の例を。
『シグナルを逆方向に変更する関数』を作るとします。
つまりBUYシグナル→SELLシグナル、SELLシグナル→BUYシグナルに変更するような関数です。
もうこの時点で、どちらを使うか分かっちゃいますね(笑)
結果は分かっていても、コードを見てみましょう!

ConvertIntoOpposite1関数は、逆シグナルを返す関数。
ConvertIntoOpposite2関数は、参照渡しによって、逆シグナルに変更する関数。



#define SELL_SIGNAL -1
#define BUY_SIGNAL 1
#define NO_SIGNAL 0

int MacdRsiSignal(double macd, double rsi)
{
//ふにゃふにゃ処理
//

if (BUY条件)
return (BUY_SIGNAL);
else if (SELL条件)
return (SELL_SIGNAL);
else
return (NO_SIGNAL);
}

int ConvertIntoOpposite1(int signal)
{
if (signal == BUY_SIGNAL)
return (SELL_SIGNAL);
else if (signal == SELL_SIGNAL)
return (BUY_SIGNAL);
else
return (NO_SIGNAL);
}

void ConvertIntoOpposite2(int &signal)
{
if (signal == BUY_SIGNAL)
signal = SELL_SIGNAL;
else if (signal == SELL_SIGNAL)
signal = BUY_SIGNAL;
else
signal = NO_SIGNAL;
}

int start()
{
double macd = iMACD(/*省略*/);
double rsi = iRSI(/*省略*/);
int signal1, signal2;

// 返り値によってシグナルを得る
signal = MacdRsiSignal(macd, rsi);
signal2 = MacdRsiSignal(macd, rsi);

// 参照渡しによってシグナルを逆転させる
ConvertIntoOpposite2(signal);

// シグナル逆転させた結果を返す
signal2 = ConvertIntoOpposite1(signal2);
}


この例だと『値の変更が目的』ですので参照渡しを行っているConvertIntoOpposite2関数がしっくりきます。


今回示した例は私の主観的な意見です。

「この場合は参照渡しの方がしっくりする」
という考えがございましたら、ご自身のフィーリングを大切にして頂きたいと思います。

開発するのは他でもなく、あなたなのでっす。

にほんブログ村 為替ブログ FX システムトレード派へ
参照渡しは、とても便利かも!その2
さて、前回に続いて
今回は、『参照渡しの便利な使い方』をご紹介します。

「参照渡しを使えば、関数の引数の値をその関数内で変更した場合
変数の値を変更することがでる
」んでしたね。

便利な使い方として

1.複数の値を返すような関数を作ることができる
2.配列を返り値にするような関数を作ることができる


でしょうか。

1.複数の値を返すような関数を作ることができる
関数を実行した結果を、呼び出し元に返すことを「値を返す」といいますが
この時返される値のことを「返り値」と言います。
MQL4の仕様上、返り値は「0個」、もしくは「1個」と決まっています。

例えば以下のコードを見てください。
これは期間20、偏差3、2、1のそれぞれのボリンジャーバンドの幅を
表示するプログラムです。


/**
* 3つの値を画面に表示する
*/
void Display(int value1, int value2, int value3)
{
Comment(DoubleToStr(value1, 0), "\n", DoubleToStr(value2, 0), "\n", DoubleToStr(value3, 0));

return ;
}

/**
* 現在のBBand(20, 3)の幅をポイント数で返す。
*/
int BBandsDev3Points()
{
double bb_upper, bb_lower;
int points;

bb_upper = iBands(Symbol(), Period(), 20, 3, 0, PRICE_CLOSE, MODE_UPPER, 0);
bb_lower = iBands(Symbol(), Period(), 20, 3, 0, PRICE_CLOSE, MODE_LOWER, 0);

points = NormalizeDouble((bb_upper-bb_lower)/Point, 0);

return (points);
}

/**
* 現在のBBand(20, 2)の幅をポイント数で返す。
*/
int BBandsDev2Points()
{
double bb_upper, bb_lower;
int points;

bb_upper = iBands(Symbol(), Period(), 20, 2, 0, PRICE_CLOSE, MODE_UPPER, 0);
bb_lower = iBands(Symbol(), Period(), 20, 2, 0, PRICE_CLOSE, MODE_LOWER, 0);

points = NormalizeDouble((bb_upper-bb_lower)/Point, 0);

return (points);
}

/**
* 現在のBBand(20, 1)の幅をポイント数で返す。
*/
int BBandsDev1Points()
{
double bb_upper, bb_lower;
int points;

bb_upper = iBands(Symbol(), Period(), 20, 1, 0, PRICE_CLOSE, MODE_UPPER, 0);
bb_lower = iBands(Symbol(), Period(), 20, 1, 0, PRICE_CLOSE, MODE_LOWER, 0);

points = NormalizeDouble((bb_upper-bb_lower)/Point, 0);

return (points);
}

//+------------------------------------------------------------------+
//| script program start function |
//+------------------------------------------------------------------+
int start()
{
int dev3points, dev2points, dev1points;
dev3points = BBandsDev3Points();
dev2points = BBandsDev2Points();
dev1points = BBandsDev1Points();

Display(dev3points, dev2points, dev1points);

return (0);
}


各関数の返り値の個数は
関数名返り値の個数
Display0
BBandsDev3Points1
BBandsDev2Points1
BBandsDev1Points1


です。
しかし「BBandsDev3Points、BBandsDev2Points、BBandsDev1Points」の3つの関数は
機能としてはかなり似ているので、できれば一つにまとめたいものです。

偏差3、2、1のボリンジャーバンドの幅を返すような関数を作れば
この願望を満たすことができます。

しかし、返り値は2つ以上返すことができない。

ん~~~困った困った。


そこで『参照渡し』という機能の登場です。
『参照渡し』をした場合、引数の値を変更すれば、変数の値も変更されるのでしたね。

上記のコードを『参照渡し』を用いて書き直したものが以下になります。

/**
* 3つの値を画面に表示する
*/
void Display(int value1, int value2, int value3)
{
Comment(DoubleToStr(value1, 0), "\n", DoubleToStr(value2, 0), "\n", DoubleToStr(value3, 0));

return ;
}

/**
* 今のBBand(20, 3)、BBand(20, 2)、BBand(20, 1)の幅のポイント数を計算する
*/
void BBandsDev321Points(int &dev3, int &dev2, int &dev1)
{
double bb_upper, bb_lower;

// Deviation 3
bb_upper = iBands(Symbol(), Period(), 20, 3, 0, PRICE_CLOSE, MODE_UPPER, 0);
bb_lower = iBands(Symbol(), Period(), 20, 3, 0, PRICE_CLOSE, MODE_LOWER, 0);
dev3 = NormalizeDouble((bb_upper-bb_lower)/Point, 0);

// Deviation 2
bb_upper = iBands(Symbol(), Period(), 20, 2, 0, PRICE_CLOSE, MODE_UPPER, 0);
bb_lower = iBands(Symbol(), Period(), 20, 2, 0, PRICE_CLOSE, MODE_LOWER, 0);
dev2 = NormalizeDouble((bb_upper-bb_lower)/Point, 0);

// Deviation 1
bb_upper = iBands(Symbol(), Period(), 20, 1, 0, PRICE_CLOSE, MODE_UPPER, 0);
bb_lower = iBands(Symbol(), Period(), 20, 1, 0, PRICE_CLOSE, MODE_LOWER, 0);
dev1 = NormalizeDouble((bb_upper-bb_lower)/Point, 0);

return ;
}


//+------------------------------------------------------------------+
//| script program start function |
//+------------------------------------------------------------------+
int start()
{
int dev3points, dev2points, dev1points;
string disp_str;
BBandsDev321Points(dev3points, dev2points, dev1points);

Display(dev3points, dev2points, dev1points);

return (0);
}

Display関数は全く変更していません。

「BBandsDev3Points、BBandsDev2Points、BBandsDev1Points」の機能を一つにまとめた関数が
BBandsDev321Points関数です(参照渡しをするために、引数の名前の前に「&」が付いています)。

start関数内で、偏差3、2、1のボリンジャーバンドの幅を代入する為の変数
「dev3points, dev2points, dev1points」を用意し、

BBandsDev321Points(dev3points, dev2points, dev1points);

のようにBBandsDev321Points関数を呼び出します。
BBandsDev321Points関数の処理が終わる頃には、
「dev3points, dev2points, dev1points」に適切な値が代入されています。


これで
1.複数の値を返すような関数を作ることができる

というイメージが湧いたでしょうか?


2.配列を返り値にするような関数を作ることができる

これに関しては、例えば

"This is a pen."
という文字列を半角スペースで分け、それぞれの結果を文字列配列に格納するStringSplit関数を作る

ことができます。
StringSplit関数の使い方のイメージとしては

string str;
string splited[20];

str = "This is a pen."

StringSplit(splited, str, " ");

//結果
//splited[0] : "This"
//splited[1] : "is"
//splited[2] : "a"
//splited[3] : "pen."


こんな感じでしょうか。

是非ご自身で実装してみてください。


2回に渡って『参照渡し』を説明しましたが、
イメージはできたでしょうか?

にほんブログ村 為替ブログ FX システムトレード派へ
Designed by aykm.
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。