2018年5月6日日曜日

[MQL4] string と datetime の加算演算は strict モードかどうかで動作が変わる

MQL4 のコンパイラは strict モードか否かで微妙に動作を変えます。

strict モードは、変数のスコープ等が厳格になっており、特別な理由が無い場合は使用すべきかと思います。 ただ、string と datetime の加算は混乱を招く仕様となっているので、注意が必要です。

参考

Updated MQL4 - MQL4 Reference

strict ではない場合、数字として扱われる

1
2
3
4
5
6
7
8
// #property strict
 
void OnStart()
{
    datetime date = D'2018.05.04 09:00:00';
    string str = "date=" + date;
    Print(str); // date=1525424400
}

datetime の実体は 1970/1/1 からの秒なので、ある意味素直な結果です。

参考

[MQL4] datetime を long にキャストすると 1970/1/1 からの秒になる | Strategy of C

strict モードの場合、文字列になる

1
2
3
4
5
6
7
8
#property strict
 
void OnStart()
{
    datetime date = D'2018.05.04 09:00:00';
    string str = "date=" + date;
    Print(str); // date=2018.05.04 09:00:00
}

これは実体云々より利便性をとった結果といえるでしょうか。 ある意味、直感的かもしれません。 どちらの方がより直感的かというのは個人の感覚に強く依存しているように思います1

さらに、このコードをコンパイルすると implicit conversion from 'number' to 'string' という Warning が出ます。

そもそも string と datetime の演算は使うべきではない

datetime は数字(1970/1/1 からの秒)という側面と、文字列(日時)という2つの側面を持つ特殊な型です。 大抵の場面で適切に処理してくれるため、便利ではあります。 しかし、混乱が起こるような場合は使用するべきではありません。

多分、同様の考えから、 strict モードでの使用時には Warning が出るのだろうと思います。

ではどうすればよいのかと言うと、秒に直したい時は unsigned long にキャスト、文字列にしたい時は TimeToStr() を使う等して、明示的に変換すると良いでしょう2

5
6
7
datetime date = D'2018.05.04 09:00:00';
printf("date=%llu", (unsigned long) date); // date=1525424400
printf("date=%s", TimeToStr(date));        // date=2018.05.04 09:00:00

個人的には文字列の加算演算もなるべく避けて printfStringFormat() を使う方が好きです3

ちなみに、printf はエイリアスだそうです

[MQL4] printf は PrintFormat のエイリアスだった | Strategy of C

  1. そこが問題 
  2. 多少記述量が増えても動作が明確な方が後々楽になります 
  3. MQL4 では定かではないですが、他の言語だとパフォーマンスが違ったりするし、慣れると読みやすいので 
?