前回、最新価格のボリンジャーバンドのσ間の値を表示するプログラムについて解説しました。今回は、それに加えてカーソル位置でのボリンジャーバンドのσ間の値を取得することを考えていきましょう。
OnChartEvent関数でマウスの動きをつかまえて、ChartXYToTimePrice関数、iBarShift関数を使い、XY座標からボリンジャーバンドの値を取得することを解説します。
ポイント
今回改良するプログラムのポイントは、カーソル位置のどんなパラメータをいかに取得するか?です。
それでは、前回のおさらいをかねてボリンジャーバンドの値を取得するiBands関数をもう一度確認してみます。
1 2 3 4 5 6 7 8 9 10 |
double iBands( string symbol, // symbol int timeframe, // timeframe int period, // averaging period double deviation, // standard deviations int bands_shift, // bands shift int applied_price, // applied price int mode, // line index int shift // shift ); |
引数が多いので面食らってしまいますが、おそれることはありません。
この関数で引数が指定しているのは、「どの通貨ペアの」「どの時間足の」「いつの」「どんなパラメーター」のボリンジャーバンドの値を取得するか?です。カーソル位置が変わることによって、上記の引数で変わるのは「いつの」です。その「いつ」に該当する具体的な引数は、第8引数 “shift”です。
shiftの説明を改めて確認してみます。
- shift
ボリンジャーバンドの値を取得するバーの位置を指定します。
現在の値を取得する場合は0、1本前なら1、という具合に指定します。
つまり、取得すべきパラメーターは「カーソル位置が、最新のバーから何本前のバーか?」に他になりません。
これで、実装すべき方針が具体的に定まりましたので、あとはカーソル位置を取得する関数のまわりを調査すればよさそうです。
カーソル位置を取得する
そもそも、カーソル位置はどのように取得するのでしょうか?
カーソルの位置はマウスの動きによって時々刻々と変わっていきます。MT4のEAやインジケーターでは、マウスが動く度にOnChartEvent関数が呼び出されます。正確に言うと、チャート上で「何かイベント」が発生する度にOnChartEvent関数が呼び出されます。その「何かイベント」の1つに「マウスが動いた」というイベントが含まれています。
ちなみに、そのイベントは多岐にわたっているので、興味のある方はこちらを参考にしてください。
OnChartEvent関数の引数と戻り値は、以下のようになっています。
1 2 3 4 5 |
void OnChartEvent(const int id, // Event ID const long& lparam, // Parameter of type long event const double& dparam, // Parameter of type double event const string& sparam // Parameter of type string events ); |
正直、意味が不明です。idは何となく意味がわかりますが、それ以外は?です。
これはOnChartEvent関数の特性上、ある意味仕方なくこのような引数になっているのです(おそらく)。
上でも説明しましたが、OnChartEvent関数は『チャート上で「何かイベント」が発生する度に』呼び出される関数です。決してマウスが動いた時用に特化された関数ではなく、汎用的な関数なのです。汎用的な関数がゆえに、引数も汎用的なネーミングになっているのです。
それでは具体的に「マウスが動いた」ときには、どのような引数が指定されるのかを確認してみます。
引数 | 値 |
int id | CHARTEVENT_MOUSE_MOVE |
long& lparam | the X coordinate マウスのX座標 |
double& dparam | the Y coordinate マウスのY座標 |
string& sparam | The string value of a bit mask describing the status of mouse buttons マウスのボタンがどのように押されているかを示すビットマスク文字列 |
必要なのはマウスのXY座標なのでlparamとdparamを使います。
ちなみに、CHARTEVENT_MOUSE_MOVEが呼び出されるようにするには、ChartSetInteger関数で設定が必要です。
しかし、今回本当に必要なのは、カーソル位置が、最新のバーから何本前のバーか?です。XY座標からバーの本数に変換しないといけません。
結論から言うと、残念ながらXY座標からバーの本数を取得する関数はありません。すこし手間がかかりますが「XY座標→時刻」「時刻→バーの本数」と2段階で求めることになります。
座標から時刻を取得する
XY座標から時刻を取得するには、ChartXYToTimePrice関数を使います。関数名からわかるように、時刻だけでなく価格も取得することができます。
1 2 3 4 5 6 7 8 |
bool ChartXYToTimePrice( long chart_id, // Chart ID int x, // The X coordinate on the chart int y, // The Y coordinate on the chart int& sub_window, // The number of the subwindow datetime& time, // Time on the chart double& price // Price on the chart ); |
- chart_id
対象のチャートIDを指定するものです。現在表示されているチャートに表示する場合は、0を指定します。 - x
取得したい時刻・価格のX座標。OnChartEvent関数で取得した値を渡します。 - y
取得したい時刻・価格のY座標。OnChartEvent関数で取得した値を渡します。 - sub_window
取得したい時刻・価格のサブウインドウ値。メインウインドウの場合は0が戻ります。 - time
取得したい時刻。 - price
取得したい価格。
戻り値は、成功したかどうかをtrue、falseで返します。
これで、カーソル位置の時刻がわかりました。繰り返しになりますが、今回本当に必要なのは、カーソル位置が、最新のバーから何本前のバーか?です。時刻からバーの本数に変換しないといけません。
時刻からバーの本数を取得する
時刻からバーの本数(何本前のバーか?)を取得するには、iBarShift関数を使います。
1 2 3 4 5 6 |
int iBarShift( string symbol, // symbol int timeframe, // timeframe datetime time, // time bool exact=false // mode ); |
- symbol
通貨ペア(例えば、”USDJPY”など)を指定するものですが、インジケーターを設定しているチャートの通貨ペアであればNULLでかまいません。 - timeframe
時間足(例えば、1時間足ならばPERIOD_H1などの定数)を指定するものですが、インジケーターを設定しているチャートの時間足であれば0でかまいません。 - time
取得したいバーの時刻。ChartXYToTimePrice関数で取得した値を渡します。 - exact
timeで指定した時刻にバーがなかった場合の値の返し方。falseならばもっとも近いバーのインデックス、trueなら-1。
戻り値は、指定した時刻におけるバーのインデックス(何本前のバーか?)です。
これで、今回本当に必要な、カーソル位置が、最新のバーから何本前のバーか?が取得することができました。
あとは、その1でやったように画面に表示するだけです。
参考までに、ChartXYToTimePrice関数、iBarShift関数を使った具体的なコードを載せておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
int x = (int)lparam; int y = (int)dparam; int window; datetime time; double price; if (ChartXYToTimePrice(0, x, y, window, time, price) ) { int shift = iBarShift(NULL, 0, time, false); if (shift > 0) { double up = iBands(NULL, 0, BB_Period, BB_Deviation, 0, PRICE_CLOSE, MODE_UPPER, shift); double lo = iBands(NULL, 0, BB_Period, BB_Deviation, 0, PRICE_CLOSE, MODE_LOWER, shift); } } |
必要な関数がわかってしまえば、後はそれぞれを丁寧につないでいくだけなので、ぜひ頑張ってコーディングしてみてください。
ご要望があれば、ソースコードを掲載しますね。
とても興味深いです。
ソースコードを掲載していただきたいです。
よろしくお願い致します。
すいません、あれから色々と試行錯誤していたら自分のやりたいことはできるようになりました。お手数おかけしました。
あと、余計なお世話でしょうが要望がなくてもコード公開していただいた方が喜ぶ人が多いと思います。
ブログ応援しています。
ソースコード公開して頂けないでしょうか
応援してます!
「ボリンジャーバンドσ間の値を表示」のソースコード公開して頂けないでしょうか
よろしくお願いいたします。