今回はボリンジャーバンドについて統計的解説込みで見ていきます
↑バナークリックでトレーディングビューのサイトに行けます
ボリンジャーバンドとは
John Bolingerさんが1980年代に考案したとされる移動平均にσ(シグマ)を合わせた線のことです。
σと呼ばれているものは標準偏差のこと。 標準偏差は統計要約値のひとつで平均に対して個々のデータがどのような分布をしているかを見るための指標です。一般に、正規分布しているデータは平均値±1σの中に約68% ±2σに約95%が入るようなっています
良く使われるのは20期間MAに対して1σ、2σ、3σ離れた位置にバンドを出すもの
日本では3σになったら戻ってくるだろう!と逆張りに良く使われていますが実際問題”今”+3σの位置にいたとしても20期間後にどの位置にいるかわからないのでそれでいつも勝てるわけでもありません。
スクイーズ(squeeze)とエクスパンション(expansion)
他の概念としてはスクイーズとエクスパンションというものがあります。意味は圧縮するとかのスクイーズ・拡大するとかっていうエクスパンションです
状態としてはボリンジャーバンドがMAの近くを等距離で推移しているか、拡大しているかというものです。
緑枠がエクスパンション赤枠がスクイーズ 白枠はバンドウォークと呼ばれる状態です。
エクスパンションは偏差が大きくなるほど大きな値動きがあること、スクイーズはあまり大きな値動きの無い状態を示していて、この状態を繰り返しています。
一方、バンドウォークと呼ばれる状態になることもあります。
バンドウォーク
バンドウォークはMAに対して1σ~2σあたりを動きながら徐々に下がる、または徐々に上がる状態
この時に逆張りをすると痛い目に遭います。
結局ボリンジャーバンドは20期間のσと言っていますが、両方向の期間に影響を与えている値なので過去20期間で-3σの位置にいたとしてもその後の20期間で+1σの価格帯という事は十分に起こりえます。
例を見てみましょう
拡大して40本のロウソクが入るようにしました。真ん中の価格帯終値を黄色の水平線で示しています。
左側の水色矢印が前半20MAのボリンジャーバンドの±3σの範囲
右側の赤矢印の枠が後半20MAのボリンジャーバンド±3σの範囲です。
前半-3σでも後半は+1σですね。こう見ると逆張りはだめなのかな~と思いますね。
ただ、違うのは終値の分布の仕方
前半はMAに近いところをうろうろしています。いわゆるスクイーズ
一方後半はMAから離れたバンドウォークをしながらのエクスパンション
つまり、エクスパンションを伴う場合はバンドウォークしがち。と言えるでしょう
スクイーズしてるときは様子見で、エクスパンションした時に仕掛ける!といった使い方が良いかもしれません。
ボリンジャーバンドの使い方
逆張りにも順張りにも使えちゃうんじゃどうすればいいのかわからない… そうなりますよね
なので、例えばマルチタイムフレームで考えてみたり、期間を複数使ったり、他のインジケーターと組み合わせてみたり…工夫はいろいろできると思います。
今回はpineでマルチタイムフレーム的な考え方で順張り方向に逆張りしていくスタンスを考えてみましょう。
少し難しいコードになりそうです。
コードを書いてみよう!
ボリンジャーバンドは3つの値が返ってくる関数ta.bb()が用意されています。
引数はta.bb(値、期間、偏差)で戻り値は[MA、+偏差、-偏差]です。
今回は1時間足のボリンジャーバンドで+1σ以上でバンドウォークを期待してロング、-1σ以下の時はショートするような戦略で行きます。その際1時間よりも短い足では反対の-3σでロング、+3σでショートするようにします。
//@version=5
strategy("ボリンジャーバンド", overlay=true, margin_long=100, margin_short=100)
[ma20,ma3u,ma3l] = ta.bb(close,20,3)
plot(ma20)
plot(ma3u)
plot(ma3l)
h1close = request.security(syminfo.tickerid,"60",close)
hsum = h1close[0*60/timeframe.multiplier]+h1close[1*60/timeframe.multiplier]+h1close[2*60/timeframe.multiplier]+h1close[3*60/timeframe.multiplier]+h1close[4*60/timeframe.multiplier]+h1close[5*60/timeframe.multiplier]+h1close[6*60/timeframe.multiplier]+h1close[7*60/timeframe.multiplier]+h1close[8*60/timeframe.multiplier]+h1close[9*60/timeframe.multiplier]+h1close[10*60/timeframe.multiplier]+h1close[11*60/timeframe.multiplier]+h1close[12*60/timeframe.multiplier]+h1close[13*60/timeframe.multiplier]+h1close[14*60/timeframe.multiplier]+h1close[15*60/timeframe.multiplier]+h1close[16*60/timeframe.multiplier]+h1close[17*60/timeframe.multiplier]+h1close[18*60/timeframe.multiplier]+h1close[19*60/timeframe.multiplier]
have = hsum/20
hvar = math.pow(math.abs(have-h1close[0*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[1*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[2*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[3*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[4*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[5*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[6*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[7*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[8*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[9*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[10*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[11*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[12*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[13*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[14*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[15*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[16*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[17*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[18*60/timeframe.multiplier]),2)+math.pow(math.abs(have-h1close[19*60/timeframe.multiplier]),2)
hdev = math.sqrt(hvar/20)
plot(have)
plot(have+hdev)
plot(have-hdev)
longCondition = ta.crossunder(close, ma3l)
if (longCondition) and close[1] > (have[1]+hdev[1])
strategy.entry("My Long Entry Id", strategy.long)
shortCondition = ta.crossover(close, ma3u)
if (shortCondition) and close[1] < (have[1] -hdev[1])
strategy.entry("My Short Entry Id", strategy.short)
諸事情により非常にダサいコードになっています。プログラム慣れしている方はfor文などでやってみると良いでしょう。トレーディングビューの限界を感じます(計算時間上限にあたってしまいました)
工夫して計算量を減らせれば何とかなるとは思うのですが、今回はしぶしぶこの形でやっています
request.security()は任意の通貨、時間足、価格を取り出せます引数は(通貨ペア、”時間”、価格)で今回は(syminfo.tickerid,"60",close)としています。syminfo.tickeridは現在チャートで選択している通貨ぺアを指定できます。
hsumでは1時間足の終値を20本分足しています。しかし、h1closeは各足にその足が所属する時間の終値が格納されています。(つまり1:15分も1:30分も1時の1時間足の終値を持つ)そのため、下位足ではsma等で指定できません。
そこで、どの足から見ても1時間分前までは同じ値が入っているので、60/timeframe.multiplier(現在の時間足:15分足なら15が入る)で1時間のローソク足の数が入るようになっています。それを、淡々と20個足しています… ダサい。
math.pow()はべき乗を指定できますa^2とは書けないので注意
a2はmath.pow(a,2)となります。3乗なら(a,3)です。 math.abs()は絶対値を求める関数 今回は2乗ですからほんとは無くても良いですが、一応
math.sqrt()は平方根を求めます√計算ですね。
ここまで見てわかるように、計算結果を求める関数にはmath.がつきます。
SDの計算式を愚直に実行しました…
さて、肝心のストラテジーは1時間足の1σ以上かつ15分足(今回の場合)で-3σを下回ったらロング
反対に1時間足の-1σ以下で15分足の+3σを上回ったらショートとしました。 なお、判定しやすいように、1時間足のσの判定はひとつ前の足で判定しています。
私はトレーディングビューに課金しているので、ディープバックテストというのが出来ます。
今回の条件は15分足でも約20年で175回しか出ないレアケースですが、一応の黒字。 勝ちやすいという事でしょうか。 ちなみに1分足でも黒字でしたが、割愛します。ディープバックテストに興味がある人は是非課金してみてください。
今回はボリンジャーバンドでしたが、意外とトレンドが出てるのか、レンジ相場なのかがわかりやすい良い指標のように思えます。 組み合わせ次第では良い戦略も考えられると思いますよ!では、今回はこの辺で!
おすすめFXアイテム
過去検証や分析はMT4かFT4、Trading viewがおすすめです。
無料が良い人はMT4で、MT4を使わせてくれる口座を使用すると良いです。おすすめはFXTF
チャート分析に毎月課金してもいいよって人はTrading viewがおすすめです。無料もあります