LoginSignup
7
6

More than 3 years have passed since last update.

MT5で新しいバーができたタイミングを判別する関数

Posted at

はじめに

MetaTrader(MT4,MT5)で動作する自動売買ソフト(EA)では、価格が変わるタイミング(ティック)ごとにトレードさせることができますが、場合によっては、新しいバーができたタイミングだけでトレードさせたいこともあります。またその方が、始値のみのモデルでバックテストできて便利だったりします。

本記事は、新しいバーができたタイミングを判別する関数についてのメモです。

参考文献

元ネタは以下の電子書籍です。参考といっても、拙著なので宣伝です。
『メタトレーダー4&5共通ライブラリによるEA開発入門』

もとのisNewBar()

参考文献の共通ライブラリに記述されている関数です。シンボルとタイムフレームを引数として、そのチャートで新しいバーができたときにtrueを返す関数です。

//新規バーのチェック
bool isNewBar(string symbol, ENUM_TIMEFRAMES tf)
{
   static datetime time = 0;
   if(iTime(symbol, tf, 0) != time)
   {
      time = iTime(symbol, tf, 0);
      return true;
   }
   return false;
}

特にこの方法が目新しいわけではなく、ネットに転がっているのと似たようなものです。ただ、以前のMQL5ではiTime()がなかったので、MT4とMT5とで別々に作らなくてはいけなかったのですが、現在のバージョンでは、MT4とMT5のどちらでも使えます。

iTime(symbol, tf, 0)で最新のバーの時刻を取得しますが、これは、最新のバーが変化していても常に始値の時刻を表します。なので、これが変われば新しいバーができたと判別できる仕組みです。

isNewBar()の使い方

普通の使い方

通常、isNewBar()はティックごとに動作する関数のなかで1回だけ使うことが多いでしょう。例えば、1分足のバーができたときに"newbar1"と表示させたい場合、

void OnTick()
{
   if(isNewBar(_Symbol, PERIOD_M1)) Print("newbar1");
}

と書けばいいだけです。Print関数をトレード関数に置き換えれば、新しいバーができたときだけトレードさせることができます。

普通でない使い方

普通でないというわけではありませんが、自分でコード書いていて気が付いただけです。同じティック関数中にisNewBar()を2回以上使った場合です。

void OnTick()
{
   if(isNewBar(_Symbol, PERIOD_M1)) Print("newbar1");
   Sleep(100);
   if(isNewBar(_Symbol, PERIOD_M1)) Print("newbar2");
}

これは一例です。Sleep(100)のところでは、ティックベースの処理を行いますが、その前後では、バーができたタイミングで処理したい場合などです。

この場合、関数の仕様上、1回目のisNewBar()では、trueを返すため、"newbar1"は表示されますが、2回目のisNewBar()では、falseとなり、"newbar2"は表示されません。

ただ、心情的には、このティックは新しいバーができたタイミングなので、2回目の呼び出しでもtrueを返してほしいところです。

新しいisNewBar()

そこで、上記の普通でない使い方にも対応できるようisNewBar()を修正してみます。

利用したのは、ティックの情報を取得するSymbolInfoTick()という関数です。これは、シンボルを引数として入力し、直近のティック情報を2番目の引数でMqlTickという構造体として返す関数です。

このMqlTickという構造体は、MQL4とMQL5とでメンバーがちょっと異なります。

MQL4: https://docs.mql4.com/constants/structures/mqltick
MQL5: https://www.mql5.com/ja/docs/constants/structures/mqltick

このなかで、時間に関係するメンバーとして、time(MQL4とMQL5の両方)とtime_msc(MQL5のみ)があります。この違いは、timeが秒単位なのに対して、time_mscがミリ秒単位ということです。

timeの方がMQL4とMQL5の両方で使えるのでいいのですが、秒単位だと、同じ秒で複数のティックが発生することもよくあります。やはり、ティックを区別するためには、ミリ秒単位の情報が必要となります。

そこで、MT5に限定ですが、time_mscを使ってisNewBar()を修正してみます。

//新規バーのチェック
bool isNewBar(string symbol, ENUM_TIMEFRAMES tf)
{
   static datetime bartime = 0;
   static long ticktime = 0;
   MqlTick tick;
   SymbolInfoTick(symbol, tick);
   if(iTime(symbol, tf, 0) != bartime)
   {
      bartime = iTime(symbol, tf, 0);
      ticktime = tick.time_msc;
      return true;
   }
   else if(ticktime == tick.time_msc) return true;
   return false;
}

static変数として、バーの開始時刻を表すbartimeに加えて、ティックの時刻を表すticktimeという変数を用意します。そして、tickという変数にティック情報を取得し、新しいバーができたときに、その時刻tick.time_mscticktimeに記憶しておきます。

こうすることで、同じティックでisNewBar()が2回目以降呼び出された場合でも、ティック時刻が同じであれば、新しいバーができたタイミングだとみなし、trueを返します。

これを使うと、さっきのisNewBar()を2回呼び出す場合でも、"newbar1"と"newbar2"の両方を表示させることができます。

おわりに

今回の記事で紹介したisNewBar()ですが、MQL4では使えないので、参考文献の共通ライブラリには、当面は採用しません。同じティックでisNewBar()を2回以上呼びたい場合、

void OnTick()
{
   bool flag_newbar = isNewBar(_Symbol, PERIOD_M1);
   if(flag_newbar) Print("newbar1");
   Sleep(100);
   if(flag_newbar) Print("newbar2");
}

のようにisNewBar()の戻り値を記憶しておけばよいでしょう。

久々のQiita記事らしく、たいていの人には関係ない情報をお届けしました。お粗末様でした。

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6