”MQL言語初見殺し”の「forを使った定型文」
MQLプログラミング言語、学習していますか?
今回は、MQL言語の学習者が初見でつまづく「forを使った定型文」について解説します。
つまづく…というよりは混乱すると書いたほうが正しいかもしれませんね。
オリジナル・インジケーターを作る際に欠かせない「for()文」。いわゆる繰り返し(ループ処理)をおこなうための命令文ですね。
オーソドックスなインジケーターをチャート上に表示させるには、全てのローソク足に合わせてインジケーターの値をプロットしていかなくてはいけません。
MetaTrader4のチャート上のローソク足ってたくさんありますよね。なので、最初に決めておいた計算式を「ローソク足本数分繰り返しなさい」という命令文を書くわけです。そのためにMQLプログラムでは繰り返し命令文=「for()」を使用することが一般的です。
for文は以下のように記述します。
for(初期化; 条件式; 更新式)
{
処理;
}
「forを使った定型文」は、インジケーターを構成する重要なソースコードの一つです。ところが、この命令文(for文)の書き方が色々と存在するために、初心者が「あれ?どれが正しいの?」と戸惑ってしまいます。
そもそもプログラムは、同じことをするための書き方(ソースコード)が色々と存在します。目的は同じでもプログラミングのやり方は人それぞれなのですね。もちろんシンプルで誰が見ても理解しやすく破綻のないソースコードがベストです。
この「forを使った定型文」=「全ローソク足を一巡して計算をおこなう処理」の書き方を、いくつか取り上げてみましょう。
forを使ったループ処理定型文【その1】
まずは、『新MT4対応 FXメタトレーダープログラミング入門』から引用します。
豊嶋 久道(著)・2015年11月1日出版
【Kindle版】900円(Kindle Unlimited会員は無料)
int limit = rates_total - prev_calculated;
for(int i = 0; i < limit; i++)
{
処理;
}
return(rates_total-1);
limitを変数として宣言しておき、そこにrates_total(=ローソク足の総数)からprev_calculated(=計算済みのローソク足の数)を引いた値を入れておきます。
ローソク足が100本あるとして(rates_total=100)、最初は1本も計算していないのでprev_calculated(=計算済みのローソク足の数)はゼロですよね。なので、limitは100です。2回目以降のループ処理では、新しくできたローソク足だけを計算しましょう(rates_total – prev_calculated)、ということです。ティックが変わるたびに全ローソク足を計算するのは無駄が多いし負荷がかかります。なので新足のみを計算するわけです。
for(int i=0; i<limit; i++)で、0からスタートしlimitが99になるまで1本づつ増やしながら(i++)、ループ処理をおこなっていく…という命令文ですね。
最後のreturn(rates_total-1)の意味がやや難しいのですが、一度全てのローソク足をプロット後に、新しくできたローソク足の処理(つまり2回目以降の処理)をする際に、新足のみを計算させるためにreturn(rates_total-1)と書いています。仮に100本のローソク足があるとすれば、1を引くことでprev_calculatedに99を入れるためですね。そうすればrates_total(100) – prev_calculated(99)=1となるので、limitは1となります。結果、最新のローソク足(i < limitまでだから、0番)のみを計算することができるようになるのですね。
forを使ったループ処理定型文【その2】
さて、同じような処理を別の書き方で表したものを見てみましょう。※厳密に言えば同じ処理ではありません。似たような処理と考えてください。
以下のソースコードはMT4のベテランHTさんが動画内で紹介されていたものです。
int limit = Bars - IndicatorCounted() -1;
if(limit < 1)limit = 1;
for(int i = limit; i >= 0; i--)
{
処理;
}
Bars(=チャートの最大ローソク足総数)からIndicatorCounted()(=変化していないローソク足の本数、最初は0,2回め以降は計算済みの本数が入る=確定足)を引き、さらにマイナス1したものをlimitに入れます。ローソク足の総数が100本(0〜99番)ならば、最初は100-0-1=99、limitは99になりますね。つまり一番左側の古いローソク足(=99番)がlimitに代入されます。
for文では、99からスタートして、ゼロになるまで(i >= 0)1本ずつマイナスしながら(i–)ループ処理をおこなっています。
新しいローソク足が完成すればBarsは101になり、計算済み足のIndicatorCounted()は100となりますね。limitは101−100−1=0となります。しかし「if(limit < 1)limit = 1;」によって、limitは1になります。つまり0番目と1番目の足を計算することになりますね。
本来ならば、最新の足(つまり0番)のみを計算すればOKなのですが、データ(値)の正確性を担保するために、「if(limit < 1)limit = 1;」を加えて、常に最新のローソク足(0番)とその次に古い足(1番)を計算する処理をおこなっているとの解説です。
forを使ったループ処理定型文【その3】
もう一つ、You TubeでMQL言語の初心者向け解説をされている「キャンドルマツ」さんの動画から、同じ部分を取り出してみます。
int limit = Bars - IndicatorCounted() -1;
for(int i = limit; i >= 0; i--)
{
処理;
}
HTさんのソースコードと似ていますね。上から2行目のコード(if(limit < 1)limit = 1;)が欠けてるだけで、あとは全く同じです。
最初は、チャート上のローソク足の総数Barsをlimitに入れ、次回以降は「変化したバーの数」マイナス1がlimitに代入されます。「キャンドルマツ」さんの説明によれば、「−1」はバグ調整で付け足してあるとのこと。 MT4のバグによってBars – IndicatorCounted()が正しい値を返してくれない場合があり、その結果2本のローソク足が残る可能性(例 100ー98=2)があるので、あえて「−1」してlimitは常に1になるようにしているとの説明です(100ー98−1=1)。その調整によって、常に2本の足(0番と1番)を繰り返し計算してプロットすることになるとのこと。このバグの存在については私も詳しくないため、説明がよくわかりませんでした。詳しくは解説動画をご覧ください。
どちらかといえばHTさんのif(limit < 1)limit = 1;処理の方が私は理解しやすいかな?と思いました。仮にlimitが0でも1でも、1を返すわけです。まあ、このあたりは好みの問題かもしれませんね。
2行目のfor文については、HTさんと同じように最新のローソク足から過去に向かって計算を進めるソースコードです。最初に紹介した『新MT4対応 FXメタトレーダープログラミング入門』のソースコードは、過去のローソク足(一番古いローソク足)を起点にして、徐々に新しいローソク足へと計算をすすめるソースコードです。
forを使ったループ処理定型文【その4】
ネットで検索すれば、以下のようなソースコードを見かけたりすることもあります。
int limit = Bars - IndicatorCounted();
for(int i = 0; i < limit; i++)
{
処理;
}
int limit = Bars - IndicatorCounted();
for(int i = limit - 1; i >= 0; i--)
{
処理;
}
すごくシンプルですね。どちらのソースコードも、2回目以降は0番目(=最新のローソク足)のみを計算する処理です。
最新のローソク足から過去に向かって計算を進めるのか、それとも過去のローソク足(一番古いローソク足)を起点にして、徐々に新しいローソク足へと計算をすすめるのかは、作りたいインジケーターによって選択します(過去足を基準に計算するインジケーターならば、過去足を起点にして新しい足へと計算をすすめるコードを書くなど)。
まとめ:人によって微妙にコードの書き方が異なる
上に挙げたとおり、プログラマーによって微妙にコードの書き方が異なったり、作りたいインジケーターによって計算順序が異なったりと、MQL初心者(プログラミング初心者)にとっては混乱する要素が満載です。
頭がかたすぎたり融通がきかな場合、こうした違いにいちいち悩まされたりするんですよね。まずは、(プログラミングとはこういうものだ)と思って、学習を進めるしかありません。