MQL4はC言語に近い文法なので、プログラミング経験がある人ほどすぐに書き始められます。ただ、FX特有の「時間足(ローソク足)」という考え方を意識せずにロジックを組むと、思わぬ問題にぶつかります。
代表的なのが、同じローソク足の中で何度もエントリーしてしまう問題です。OnTick()は価格が動くたび(ティックごと)に呼ばれるため、条件を満たしている間は、1本のローソク足が終わるまで注文を繰り返してしまいます。
ローソク足の始値で1回だけ計算する
解決策はシンプルで、「新しいローソク足ができた最初のティックでだけロジックを計算し、次のローソク足ができるまでは何もしない」ようにします。
こうすると処理が軽くなり、同じローソク足の中で計算を繰り返したり、注文を大量に出したりすることがなくなります。新しいローソク足ができたかどうかの判定方法は、主に次の3つです。
Time[0]で判定する(おすすめ)
datetime Time[]
Time[]は、各ローソク足の開始時刻が入った配列です。Time[0]には、いま形成中のローソク足の開始時刻が入っています。
新しいローソク足ができるとTime[0]の値が変わるので、前回の値と比べれば「新しい足になったか」がわかります。ローソク足の本数やティック数に左右されないため、もっとも確実な方法です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
bool IsNewBar() { static datetime lastBarTime = 0; // 前回と同じ開始時刻なら、まだ同じローソク足 if(lastBarTime == Time[0]) return(false); lastBarTime = Time[0]; return(true); } void OnTick() { // 新しいローソク足でなければ何もしない if(!IsNewBar()) return; // ここにローソク足ごとに1回だけ行う処理を書く ... } |
この書き方だと、EAをチャートに入れた直後の最初のティックでも1回処理が走ります。入れた時点のローソク足は見送りたい場合は、OnInit()の中で lastBarTime に Time[0] を入れておきます(その場合は static ではなくグローバル変数にします)。
チャートとは別の時間足(例えば5分足チャートで1時間足の切り替わり)を判定したいときは、Time[0] の代わりに iTime(NULL, PERIOD_H1, 0) を使えば同じ考え方で判定できます。
Barsで判定する
int Bars
Barsは、現在のチャートにあるバー(ローソク足)の総数です。新しいローソク足ができるとカウントが1つ増え、同じローソク足の間は変わりません。この性質を利用する方法です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
int nowbar; int OnInit() { ... nowbar = Bars; ... } void OnTick() { // バーの総数が変わっていなければ何もしない if(nowbar == Bars){ return; } else{ nowbar = Bars; } ... } |
手軽ですが、Barsには次の弱点があります。
- 最大バー数に達すると増えなくなる:MT4の「ツール」→「オプション」→「チャート」にある「チャートの最大バー数」に達すると、新しい足ができてもBarsが増えず、判定が止まってしまいます。
- 履歴の読み込みで誤判定する:過去データがダウンロードされてチャートに足が追加されると、新しい足ができていなくてもBarsが増えるため、「新しい足」と誤判定することがあります。
Volume[0]で判定する
long Volume[]
Volume[]には各ローソク足のティック出来高(ティックの回数)が入っています。新しいローソク足の最初のティックでは Volume[0] が1になる、という性質を利用する方法です。
MT4に付属するサンプルEA「Moving Average.mq4」でも、次のように使われています。
|
1 2 3 4 5 6 7 8 |
void CheckForOpen() { double ma; int res; //--- go trading only for first tiks of new bar if(Volume[0] > 1) return; ... } |
ただし、通信の遅れや処理の重さなどで最初のティックを取りこぼすと、EAが受け取った時点ですでに Volume[0] が2以上になっていることがあります。その場合、そのローソク足では一度も処理が走らず、丸ごと見送られてしまいます。
3つの方法の比較
| 方法 | 判定の仕組み | 注意点 | おすすめ度 |
| Time[0] | ローソク足の開始時刻が変わったか | 特になし | ◎ |
| Bars | チャートのバー数が増えたか | 最大バー数に達すると判定が止まる/履歴の読み込みで誤判定する | △ |
| Volume[0] | 現在の足のティック数が1か | 最初のティックを取りこぼすと、その足を丸ごと見送る | △ |
これから書くEAでは、Time[0]で判定する方法を使うのが安心です。Barsを使った既存のEAも、長期間動かしていると最大バー数に達して突然エントリーしなくなることがあるため、Time[0]での判定に置き換えておくことをおすすめします。




















