「相場のボラティリティを把握するために、ボリンジャーバンドのσ間の値を出して欲しい」
というオーダーを妻からもらいました。
現在表示しているチャート上に、現在価格でのボリンジャーバンドのσ間の値、+3σ〜-3σの値をpipsで表示して欲しいとの要望です。
うまく説明できているかわからないので図で説明すると、下の図の赤い矢印間の値ということです。
ボリンジャーバンドの値を取得するiBands関数の使い方を説明しながら、このインジケーターを作成するためのポイントを解説していきます。
インジケーターの仕様
やるべきことはそんなに難しくないので、まずは大まかに仕様を決めます。
- ボリンジャーバンドの任意の期間(20など)、標準偏差間(±3σ、±2σ、±1σ)の間隔をpipsで表示する
- 表示する場所は、チャートの左上に任意の色・サイズでテキスト表示する
- 最新価格が更新されたタイミングで表示する値を反映する
ざっくりとこんな感じです。
まったく仕様を考えずにいきなりコードを打ち込みはじめると、あいまいなところがコードに落とし込めなくなり、結果不具合・バグにつながります。
かといって、商用のプログラムを組むわけではないので、ガチガチに仕様を決めるのも気が重くなりますし、楽しくありません。
インジケーターの「キモ」となる部分だけをしっかり決めておくのが大事だと思います。
ユーザーが設定可能なパラメータ
仕様のところで「任意」と書いた部分は、ユーザーが設定できるようにします。
- 表示するテキストの色
- 表示するテキストサイズ
- ボリンジャーバンドの期間
- ボリンジャーバンドの標準偏差
この4つがユーザーが指定可能なパラメータです。
プログラムの冒頭部分に宣言します。
1 2 3 4 |
input int Label_Size = 10; // フォントサイズ input color Label_Color = clrRed; // フォント色 input int BB_Period = 21; // ボリンジャーバンドの移動平均線の期間 input int BB_Deviation = 3; // ボリンジャーバンドのかけ率 |
初期化
初期化、つまりOnInit関数でやるべきことを考えます。
価格が変動するたびに標準偏差間の値をチャート上に表示する必要がありますが、表示するためのテキストエリアをまず設定する必要があります。
MetaTraderでテキストを表示するには「テキスト」「ラベル」という2つのオブジェクトがあります。
今回のように、ローソク足などが増えていって画面がスクロールしても、同じ場所に表示する必要がある場合は「ラベル」を使います。
1 2 3 4 5 6 7 8 9 |
ObjectCreate(0, LABEL_NEW, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, LABEL_NEW ,OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER); ObjectSetInteger(0, LABEL_NEW, OBJPROP_XDISTANCE, 10 + Label_Size); ObjectSetInteger(0, LABEL_NEW, OBJPROP_YDISTANCE, 20 + Label_Size); ObjectSetString(0, LABEL_NEW, OBJPROP_FONT, "MS ゴシック"); ObjectSetInteger(0, LABEL_NEW, OBJPROP_COLOR, Label_Color); ObjectSetInteger(0, LABEL_NEW, OBJPROP_FONTSIZE, Label_Size); ObjectSetInteger(0, LABEL_NEW, OBJPROP_READONLY, false); ObjectSetInteger(0, LABEL_NEW, OBJPROP_SELECTABLE, false); |
ラベルオブジェクトを表示するには、ObjectCreateでオブジェクトを作成し、ObjectSetInteger、ObjectSetStringでオブジェクト(テキストラベル)のプロパティ(表示場所、フォントなど)を設定していきます。
上記のコードでは、オブジェクトを作成(1行目)して、テキストの表示位置(2〜4行目)、フォント(5〜7行目)、読み書き属性(8行目)、選択可否(9行目)を設定しています。
ObjectCreate関数は、次のような引数と戻り値になっています。
1 2 3 4 5 6 7 8 9 |
bool ObjectCreate( long chart_id, // chart ID string object_name, // object name ENUM_OBJECT object_type, // object type int sub_window, // window index datetime time1, // time of the first anchor point double price1, // price of the first anchor point ); |
chart_idは、作成するオブジェクトをどのチャートに表示するかを指定するものです。現在表示されているチャートに表示する場合は、0を指定します。
object_nameは、作成するオブジェクトの名前です。同じチャート内でユニークな名前にする必要があります。
この後、ObjectSetInteger関数などでオブジェクトのプロパティを設定していきますが、そのときにオブジェクトを一意に識別するために必ず使う必要があります。プログラマが好きな文字列(例えば、”Label1″や”BBValue_Label”など)をつけることができます。
こういう好きに命名してよい文字列は、オブジェクトが増えたり、仕様を変更した場合にえてして変えたくなります。
プログラム全体で使う固定の値・文字列は、直に数値や文字列を書き込むのではなくマクロ化しておきましょう。
マクロは#defineを使って記述します。
以下のコードでは、プログラム中のLABEL_NEWは”LabelName_New”という文字列として取り扱いなさい、ということになります。慣例的に、マクロはプログラムの冒頭に書かれます。
1 2 3 |
#define LABEL_NEW "LabelName_New" |
さて、オブジェクトのプロパティは、ObjectSetInteger関数、ObjectSetString関数で設定します。
1 2 3 4 5 6 |
bool ObjectSetInteger( long chart_id, // chart identifier string object_name, // object name int prop_id, // property long prop_value // value ); |
1 2 3 4 5 6 |
bool ObjectSetString( long chart_id, // chart identifier string object_name, // object name int prop_id, // property string prop_value // value ); |
どちらの関数も、ObjectCreate関数でオブジェクトを作成するときに指定したオブジェクトの名前を指定して、prop_idで設定したい項目、prop_valueで実際の値を指定することになります。
今回指定した項目についての詳細は省略しますが、Object Property(オブジェクトに指定するプロパティ)を参考に読み解いてみてください。
1 2 3 4 5 6 7 8 9 |
ObjectCreate(0, LABEL_NEW, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, LABEL_NEW ,OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER); ObjectSetInteger(0, LABEL_NEW, OBJPROP_XDISTANCE, 10 + Label_Size); ObjectSetInteger(0, LABEL_NEW, OBJPROP_YDISTANCE, 20 + Label_Size); ObjectSetString(0, LABEL_NEW, OBJPROP_FONT, "MS ゴシック"); ObjectSetInteger(0, LABEL_NEW, OBJPROP_COLOR, Label_Color); ObjectSetInteger(0, LABEL_NEW, OBJPROP_FONTSIZE, Label_Size); ObjectSetInteger(0, LABEL_NEW, OBJPROP_READONLY, false); ObjectSetInteger(0, LABEL_NEW, OBJPROP_SELECTABLE, false); |
実際に値を表示する
実際に値を更新するのは、値が動いたとき、つまりOnCalculate関数が呼び出されたときです。
OnCalculate関数では、現在のボリンジャーバンドの2つの標準偏差値(例えば、+3σと-3σ)を取得し、その値の差をpipsで表示することになります。
ボリンジャーバンドの値を取得するには、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 ); |
なんだか引数がやたら多いですが、丁寧に見ていけば決して難しくありません。
- symbol
通貨ペア(例えば、”USDJPY”など)を指定するものですが、インジケーターを設定しているチャートの通貨ペアであればNULLでかまいません。 - timeframe
時間足(例えば、1時間足ならばPERIOD_H1などの定数)を指定するものですが、インジケーターを設定しているチャートの時間足であれば0でかまいません。 - period
ボリンジャーバンドの移動平均線の期間です。冒頭でユーザーが任意に変えられるように変数設定をしました(BB_Period)。 - deviation
ボリンジャーバンドの掛け率、±3σならば3、±2σなら2を指定します。冒頭でユーザーが任意に変えられるように変数設定をしました(BB_Deviation)。 - band_shift
ボリンジャーバンドを表示するときに、右方向にずらすバーの本数をしていします。今回は0にしました。 - appled_price
ボリンジャーバンドの値を計算するために使う価格を指定します。今回は、終値を使うようにしたのでPRICE_CLOSEとしました。 - mode
ボリンジャーバンドは移動平均線を中心に上側と下側に線があるので、上側の値を取得する場合はMODE_UPPER、下側の値を取得する場合はMODE_LOWERを指定します。 - shift
ボリンジャーバンドの値を取得するバーの位置を指定します。現在の値をとる場合は0、1本前なら1、という具合に指定します。
戻り値は、ボリンジャーバンドの値です。
1 2 |
double up = iBands(NULL, 0, BB_Period, BB_Deviation, 0, PRICE_CLOSE, MODE_UPPER, 0); double lo = iBands(NULL, 0, BB_Period, BB_Deviation, 0, PRICE_CLOSE, MODE_LOWER, 0); |
今回は±σ間の値を取得する必要があるため、+σ、−σの値をそれぞれ取得します。
あとは、先に作成したラベルオブジェクトにテキストとして表示します。
移動平均線の期間、掛け率、PIPS、価格を以下のように表示することとします。
(21/3)現在価格:27.4 (112.983 – 112.710)
ところで価格からPIPSへの計算は、どのようにすればよいのでしょうか?
ドル円(USDJPY)の場合は、1PIPSは0.01円です。
ユーロドル(EURUSD)の場合は、1PIPSは0.0001ドルです。
つまり、少なくとも価格の差分に固定値を乗算するだけで実現するのは難しそうです。必ず何かしらの条件分岐が入りそうです。では、通貨ペアごとに係数をすべて持たないといけないのでしょうか?
もちろんそんなやっかいなことをする必要はなく、すこし計算すればすべての通貨ペアに対応することができます。
価格からPIPSへの変換
価格からPIPS変換には、FX業者の提示レートの桁数とPointの理解が必要になります。
MT4では、Pointという変数が通貨ペアごとに設定されています。これは提示レートの最小変動単位をあらわしています。
少しわかりづらいので、具体的な値をもとに説明します。
USDJPYで112,98、112.99と値動きをしている場合、Pointは0.01(2桁業者)。
USDJPYで112.983、112.980と値動きをしている場合、Pointは0.001(3桁業者)。
EURUSDで1.1735、1.1734と値動きをしている場合、Pointは0.0001(4桁業者)。
EURUSDで1.17359、1.17355と値動きをしている場合、Pointは0.00001(5桁業者)。
ここでもう1度、1PIPSと実際の通貨単位の関係を思い出してみましょう。
USDJPYの場合・・・1PIPSは0.01円
EURUSDの場合・・・1PIPSは0.0001ドル。
つまり、2桁/4桁業者の場合、「PIPS=POINT」となり、3桁/5桁業者の場合、「PIPS=10POINT」となることがわかります。
これを今回のインジケーターの仕様である「価格からPIPSへの変換」で便利にプログラムを組むことを考えると、
PIPS = 価格の差分 × 係数
という風に書きたくなります。つまり、PipsPerPrice とでもネーミングした係数を準備しておけばよさそうです。
この係数は、同じ事業者を使っている限りは「価格ペア」のみで決定する要素なので、初期化つまりOnInit関数で定義すればよさそうです。
1 2 3 4 5 6 |
// 価格からPIPS換算するための係数 gPipsPerPrice = 1 / Point; if (Digits == 3 || Digits == 5) { gPipsPerPrice /= 10; } |
実際の価格を表示するところでは、以下のように計算します。
1 2 3 4 5 6 7 8 9 |
double val = (up - lo) * gPipsPerPrice; string str1 = IntegerToString(BB_Period); string str2 = IntegerToString(BB_Deviation, 0); string str3 = DoubleToStr(val, 1); string str4 = DoubleToStr(up, Digits); string str5 = DoubleToStr(lo, Digits); string tmp = "(" + str1 + "/" + str2 + ")現在価格:" + str3 + " (" + str4 + " - " + str5 + ")"; ObjectSetString(0, LABEL_NEW, OBJPROP_TEXT, tmp); |
これで価格が更新されるたびに、現在価格におけるボリンジャーバンドの間隔がPIPSとして表示されます。
さらなる改良
以上、ボリンジャーバンドの値を表示するインジケーターのポイント解説は終わります。
ただ、これだけでは面白くないので、カーソルを動かすとカーソル位置のボリンジャーバンドの値も表示するように改良したいと思います。
その2に続きます。
コメント