mt4 (MetaTrader4)使い倒シストレ

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


にほんブログ村 為替ブログ FX システムトレード派へ
--/--/--(--) --:--:-- | スポンサー広告 | Trackback(-) | Comment(-)
参照渡しは、とても便利かも!その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 システムトレード派へ
スポンサーサイト
参照渡しは、とても便利かも!
以前に書いた【グローバル変数を使わずに健康的に】の記事の中で
『参照渡し』を使ったコードを書いたところ、

「&」とは何を意味するのでしょうか?

というご質問をいただきました。
そこで、『参照渡し』についての解説と、便利に使える方法を
いくつかご紹介したいと思います。

まずは『参照渡し』についてです。

MQL4では、関数の引数の値をその関数内で変更しても
変数の値を変更することはできません。


どういうことかというと、案の定ですが…


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

void func(int arg0) {
arg0++;
}

int start()
{
int param1 = 0;

func(param1);

Comment(param1);
}

func関数とstart関数を定義しました。

・func関数はarg0という引数を受け取り、arg0をインクリメント(1を加算)する関数です。
・start関数はparam1という変数を定義し、func関数を呼び出しています。

この時Comment関数によって表示される値は、
MQL4の仕様では、『0』のままなんです。

つまり
MQL4では、関数の引数【arg0】の値【0】をその関数内で変更【arg0++】しても
変数の値【param1】を変更することはできません【0のまま】。

ってことなんですね。

そこで『参照渡し』の登場です。
『参照渡し』を使えば、関数の引数の値をその関数内で変更した場合
変数の値を変更することができます。


使い方は簡単です。
関数宣言の引数名の前に「&」をつけるだけです。

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

int start()
{
int param1 = 0;

func(param1);

Comment(param1);
}


今度はComment関数によって表示される値が『1』になります。
param1の値がちゃんとインクリメントされていますね。

つまり、
『参照渡し』を使えば、関数の引数【arg0】の値【0】をその関数内で変更【arg0++】した場合
変数の値【param1】を変更することができます【1になる!】。

ってことなんです。


これが『参照渡し』と呼ばれる方法です。
実はMQL4の標準関数にも、『参照渡し』は多用されています。
配列関数群の半分くらいに『参照渡し』が使われています。
(参照渡しは配列に使うこともできます)


int ArrayCopy( object&dest[], object source[], int start_dest=0, int start_source=0, int count=WHOLE_ARRAY)
int ArrayCopyRates( double&dest_array[], string symbol=NULL, int timeframe=0)
int ArrayCopySeries( double&array[], int series_index, string symbol=NULL, int timeframe=0)
int ArrayInitialize( double&array[], double value)
int ArrayResize( object&array[], int new_size)
bool ArraySetAsSeries( double&array[], bool set)
int ArraySort( double&array[], int count=WHOLE_ARRAY, int start=0, int sort_dir=MODE_ASCEND)


これはつまり、
この関数に渡した変数は、何かしら変化しますよ~。
ってことなんですね。
(ArrayResize関数は、渡した配列のサイズ(大きさ)を変更する関数です。)

『参照渡し』のイメージはつかめたでしょうか?

さて、続いて便利に使える方法です。

が…


次回につづく!!

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