2018年6月7日木曜日

[MQL4] カスタムインジケーターを最新値で更新する方法2種

2019/06/05 追記
コードを少し修正しました。 理由については以下にまとめてあります。 [カスタムインジケーターを更新する際、最新値だけでは足りない](https://strategyofc.blogspot.com/2019/06/mql4.html)
MQL のカスタムインジケーターは便利ですが、 作り方を間違えると不思議な動作をするので注意が必要です。 今回は最新(右端)のインジケーターの値が更新されない問題について書いてみたいと思います。 ### NG な例 まず問題点を説明するために、単純に終値を結ぶだけのカスタムインジケーターを作ってみました。 ```mq4 #property strict #property indicator_chart_window #property indicator_buffers 1 #property indicator_plots 1 //--- plot Close #property indicator_label1 "Close" #property indicator_type1 DRAW_LINE #property indicator_color1 clrRed #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- indicator buffers double Buffer[]; int OnInit() { SetIndexBuffer(0,Buffer); return INIT_SUCCEEDED; } int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { if (rates_total == 0) { return 0; } int num_uncalculated = rates_total - prev_calculated; for (int i = num_uncalculated - 1; i >= 0; i--) { Buffer[i] = close[i]; } // return value of prev_calculated for next call return rates_total; } ``` これをチャートに適用すると以下のように描画されました。 一見、正しく動作しているように見えますが、黄色の丸の中をよく見ると、値が終値からずれてしまっています。
これは、描画した瞬間の終値で値が確定し、その後更新されないことに起因します。 このインジケーターをリアルタイムチャートに適用させ続けると以下のようになります。
よく見てください。終値に追従しなければならないのに、始値に張り付いています。 描画した瞬間、つまり足が出来た瞬間は「始値=終値」なので、このような動作になってしまうわけです。 ### 解決方法1 - 戻り値を変更する `OnCalculate()` の戻り値は**次の計算時に `prev_calculated` として与えられます**。 つまり、この値を `rates_total - 1` にすることで、常に `num_uncalculated` が 1 以上になり、再計算が行われます。 ```mq4 `first-line: 40; highlight: 41; // return value of prev_calculated for next call return rates_total - 1; } ``` ### 解決方法2 - 最新値を常に計算する 以下のように `num_uncalculated` が 0 の場合も `Buffer[0]` が更新されるようにします。 ```mq4 `first-line: 35; highlight: 36; int num_uncalculated = rates_total - prev_calculated; for (int i = num_uncalculated; i >= 0; i--) { Buffer[i] = close[i]; } // return value of prev_calculated for next call return rates_total; } ``` なお、`Buffer[0]` だけを強制的に更新すると、タイミングによっては値が最新にならない可能性があります。 > 参考 > > [カスタムインジケーターを更新する際、最新値だけでは足りない | Strategy of C](https://strategyofc.blogspot.com/2019/06/mql4.html) ### どちらを使ったら良いか? どちらも、最終的に行われる計算は同じですし、 どちらを使っている例も見かけるので、どちらでも良いかと思います。 ただ、更新すべき足が複数本になる場合マルチタイムフレーム対応のインジケーター等は、方法2の方が良いかもしれません。 更新すべき足の本数を直前で決められるからです。
2018/6/8 追記
[[MQL4] マルチタイムフレーム対応インジケーターの作り方](https://strategyofc.blogspot.com/2018/06/mql4.html) を書きました。 この中で複数本を常に更新するサンプルを公開しています。