色んなトレードノウハウを調べては、自作のEAを作っているのですが、ボリンジャーバンドの幅(特に−2σ〜+2σ)をチェックするトレードノウハウが多い。
常にボリンジャーのバンド幅をチャート上に表示していた方が便利なので、今現在の幅がどのくらいなのかを確認できる簡単なインジケーターを作ってみました。
実行結果
チャートの左上に、常に表示します。ポイント表示だけでなく、pips表示も入れました。

インジケーターダウンロード
一応、ソースを公開して解説していますが、不要な方もいると思うので。
こちらからダウンロードしてください。
MQL4ソースコード
たいしたコードではないので公開。
//+------------------------------------------------------------------+
//| bb_bands_length_output.mq4 |
//| Copyright 2020, Yanoteck |
//| https://investment-vmoney.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Yanoteck"
#property link "https://investment-vmoney.com/"
#property version "1.00"
#property strict
#property indicator_chart_window
#include <MovingAverages.mqh>
#property indicator_chart_window
#property indicator_buffers 7
#property indicator_color1 Red
#property indicator_color2 SlateGray
#property indicator_color3 SlateGray
#property indicator_color4 SlateGray
//--- indicator parameters
input int InpBandsPeriod=20; // 期間
input int InpBandsShift=0; // 表示移動
input double InpBandsDeviations=2.0; // 偏差2
input double InpBandsDeviations3=3.0; // 偏差3
input double InpBandsDeviations1=1.0; // 偏差1
extern int On_BandsDeviations1=1; //偏差1の表示 On[1]/Off[0]
//--- buffers
double ExtMovingBuffer[];
double ExtUpperBuffer[];
double ExtLowerBuffer[];
double ExtStdDevBuffer[];
double ExtUpper1Buffer[];
double ExtLower1Buffer[];
double ExtUpper3Buffer[];
double ExtLower3Buffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- indicator buffers mapping
//--- 1 additional buffer used for counting.
IndicatorBuffers(8);
IndicatorDigits(Digits);
//--- middle line
SetIndexStyle(0,DRAW_LINE);
SetIndexBuffer(0,ExtMovingBuffer);
SetIndexShift(0,InpBandsShift);
SetIndexLabel(0,"Bands SMA");
//--- upper band
SetIndexStyle(1,DRAW_LINE);
SetIndexBuffer(1,ExtUpperBuffer);
SetIndexShift(1,InpBandsShift);
SetIndexLabel(1,"Band2 Upper");
//--- lower band
SetIndexStyle(2,DRAW_LINE);
SetIndexBuffer(2,ExtLowerBuffer);
SetIndexShift(2,InpBandsShift);
SetIndexLabel(2,"Band2 Lower");
//--- upper3 band
SetIndexStyle(3,DRAW_LINE);
SetIndexBuffer(3,ExtUpper3Buffer);
SetIndexShift(3,InpBandsShift);
SetIndexLabel(3,"Band3 Upper");
//--- lower3 band
SetIndexStyle(4,DRAW_LINE);
SetIndexBuffer(4,ExtLower3Buffer);
SetIndexShift(4,InpBandsShift);
SetIndexLabel(4,"Band3 Lower");
//--- upper1 band
SetIndexStyle(5,DRAW_LINE);
SetIndexBuffer(5,ExtUpper1Buffer);
SetIndexShift(5,InpBandsShift);
SetIndexLabel(5,"Band1 Upper");
//--- lower1 band
SetIndexStyle(6,DRAW_LINE);
SetIndexBuffer(6,ExtLower1Buffer);
SetIndexShift(6,InpBandsShift);
SetIndexLabel(6,"Band1 Lower");
//--- work buffer
SetIndexBuffer(7,ExtStdDevBuffer);
//--- check for input parameter
if(InpBandsPeriod<=0)
{
Print("Wrong input parameter Bands Period=",InpBandsPeriod);
return(INIT_FAILED);
}
//---
SetIndexDrawBegin(0,InpBandsPeriod+InpBandsShift);
SetIndexDrawBegin(1,InpBandsPeriod+InpBandsShift);
SetIndexDrawBegin(2,InpBandsPeriod+InpBandsShift);
SetIndexDrawBegin(4,InpBandsPeriod+InpBandsShift);
SetIndexDrawBegin(5,InpBandsPeriod+InpBandsShift);
SetIndexDrawBegin(6,InpBandsPeriod+InpBandsShift);
//--- initialization done
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
Comment("");
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
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[])
{
//---
//ボリンジャーバンド
double bb_3;
double bb_2;
double bb_1;
double bb_center;
double bb_M1;
double bb_M2;
double bb_M3;
//1バー前のボリンジャーバンド
double bb_3_1;
double bb_2_1;
double bb_1_1;
double bb_center_1;
double bb_M1_1;
double bb_M2_1;
double bb_M3_1;
//+2シグマ ー ー2シグマの間隔
double bb_2_M2;
double bb_2_M2_digit;
double bb_3_M2;
double bb_3_M2_digit;
//ボリンジャーバンドの値を取得
bb_1 = iBands(NULL,PERIOD_CURRENT,InpBandsPeriod,1,0,PRICE_CLOSE,1,0);
bb_2 = iBands(NULL,PERIOD_CURRENT,InpBandsPeriod,2,0,PRICE_CLOSE,1,0);
bb_3 = iBands(NULL,PERIOD_CURRENT,InpBandsPeriod,3,0,PRICE_CLOSE,1,0);
bb_center = iBands(NULL,PERIOD_CURRENT,InpBandsPeriod,2,0,PRICE_CLOSE,0,0);
bb_M1 = iBands(NULL,PERIOD_CURRENT,InpBandsPeriod,1,0,PRICE_CLOSE,2,0);
bb_M2 = iBands(NULL,PERIOD_CURRENT,InpBandsPeriod,2,0,PRICE_CLOSE,2,0);
bb_M3 = iBands(NULL,PERIOD_CURRENT,InpBandsPeriod,3,0,PRICE_CLOSE,2,0);
//1バー前のボリンジャーバンドの値を取得
bb_1_1 = iBands(NULL,PERIOD_CURRENT,InpBandsPeriod,1,0,PRICE_CLOSE,1,1);
bb_2_1 = iBands(NULL,PERIOD_CURRENT,InpBandsPeriod,2,0,PRICE_CLOSE,1,1);
bb_3_1 = iBands(NULL,PERIOD_CURRENT,InpBandsPeriod,3,0,PRICE_CLOSE,1,1);
bb_center_1 = iBands(NULL,PERIOD_CURRENT,InpBandsPeriod,2,0,PRICE_CLOSE,0,1);
bb_M1_1 = iBands(NULL,PERIOD_CURRENT,InpBandsPeriod,1,0,PRICE_CLOSE,2,1);
bb_M2_1 = iBands(NULL,PERIOD_CURRENT,InpBandsPeriod,2,0,PRICE_CLOSE,2,1);
bb_M3_1 = iBands(NULL,PERIOD_CURRENT,InpBandsPeriod,3,0,PRICE_CLOSE,2,1);
//ボリンジャーバンドの上下幅
bb_2_M2 = NormalizeDouble(bb_2 - bb_M2,3);
bb_2_M2_digit = NormalizeDouble(bb_2_M2 * 100,4);
bb_3_M2 = NormalizeDouble(bb_3 - bb_M3,3);
bb_3_M2_digit = NormalizeDouble(bb_3_M2 * 100,4);
//print
Comment("\n\n[Bollinger bands info]\n\n" +
"-2σ ~ +2σ = " + string(bb_2_M2) + " (" + string(bb_2_M2_digit) + "pips)" + "\n\n" +
"-3σ ~ +3σ = " + string(bb_3_M2) + " (" + string(bb_3_M2_digit) + "pips)" + "\n\n");
//Draw Bollinger Bands
int i,pos;
//---
if(rates_total<=InpBandsPeriod || InpBandsPeriod<=0)
return(0);
//--- counting from 0 to rates_total
ArraySetAsSeries(ExtMovingBuffer,false);
ArraySetAsSeries(ExtUpperBuffer,false);
ArraySetAsSeries(ExtLowerBuffer,false);
ArraySetAsSeries(ExtStdDevBuffer,false);
ArraySetAsSeries(ExtUpper3Buffer,false);
ArraySetAsSeries(ExtLower3Buffer,false);
ArraySetAsSeries(ExtUpper1Buffer,false);
ArraySetAsSeries(ExtLower1Buffer,false);
ArraySetAsSeries(close,false);
//--- initial zero
if(prev_calculated<1)
{
for(i=0; i<InpBandsPeriod; i++)
{
ExtMovingBuffer[i]=EMPTY_VALUE;
ExtUpperBuffer[i]=EMPTY_VALUE;
ExtLowerBuffer[i]=EMPTY_VALUE;
ExtUpper3Buffer[i]=EMPTY_VALUE;
ExtLower3Buffer[i]=EMPTY_VALUE;
ExtUpper1Buffer[i]=EMPTY_VALUE;
ExtLower1Buffer[i]=EMPTY_VALUE;
}
}
//--- starting calculation
if(prev_calculated>1)
pos=prev_calculated-1;
else
pos=0;
//--- main cycle
for(i=pos; i<rates_total && !IsStopped(); i++)
{
//--- middle line
ExtMovingBuffer[i]=SimpleMA(i,InpBandsPeriod,close);
//--- calculate and write down StdDev
ExtStdDevBuffer[i]=StdDev_Func(i,close,ExtMovingBuffer,InpBandsPeriod);
//--- upper line
ExtUpperBuffer[i]=ExtMovingBuffer[i]+InpBandsDeviations*ExtStdDevBuffer[i];
//--- lower line
ExtLowerBuffer[i]=ExtMovingBuffer[i]-InpBandsDeviations*ExtStdDevBuffer[i];
//--- upper line3
ExtUpperBuffer[i]=ExtMovingBuffer[i]+InpBandsDeviations3*ExtStdDevBuffer[i];
//--- lower line3
ExtLowerBuffer[i]=ExtMovingBuffer[i]-InpBandsDeviations3*ExtStdDevBuffer[i];
if(On_BandsDeviations1 != 0){
//--- upper line1
ExtUpperBuffer[i]=ExtMovingBuffer[i]+InpBandsDeviations1*ExtStdDevBuffer[i];
//--- lower line1
ExtLowerBuffer[i]=ExtMovingBuffer[i]-InpBandsDeviations1*ExtStdDevBuffer[i];
}
//---
}
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
//| Calculate Standard Deviation |
//+------------------------------------------------------------------+
double StdDev_Func(int position,const double &price[],const double &MAprice[],int period)
{
//--- variables
double StdDev_dTmp=0.0;
//--- check for position
if(position>=period)
{
//--- calcualte StdDev
for(int i=0; i<period; i++)
StdDev_dTmp+=MathPow(price[position-i]-MAprice[position],2);
StdDev_dTmp=MathSqrt(StdDev_dTmp/period);
}
//--- return calculated value
return(StdDev_dTmp);
}
//+------------------------------------------------------------------+
ベースソースは、MT4インストール時に最初から入っているボリンジャーバンドのカスタムインジケーターの「Bands.mq4」です。
これに、偏差1と3も表示する処理を入れて、それぞれの偏差の上下バンドを計算。ついで、pipsの計算も。Comment関数で表示するだけの簡単なものです。
偏差1のボリンジャーバンドは表示すると、チャートがぐちゃぐちゃになって、ウザい時もあるで、パラメーターでON/OFFが出来るようにしました。


本当はチェックボックスにしたかったけど、出来るんかな??。調べても分からなかった。
ソース解説
ボリンジャーバンドの各偏差の値を取得
iBands関数で、それぞれの偏差の値を取得。
bb_1 = iBands(NULL,PERIOD_CURRENT,20,1,0,PRICE_CLOSE,1,0);
iBandsの仕様はMQL4の公式リファレンスを参照してください。

ボリンジャーバンドの上下幅を計算して小数点の桁数丸め
NormalizeDouble関数を使って、桁数を丸める処理をいれました。これを入れないと、小数点が14桁常に表示して見づらい。
bb_2_M2 = NormalizeDouble(bb_2 - bb_M2,3);
このままだとポイント表示なので、pips表示用に計算。ポイントを100倍すればpipsになります。
bb_2_M2_digit = NormalizeDouble(bb_2_M2 * 100,4);
問題点
NormalizeDouble関数は、指定小数点で桁を丸める処理なのですが、たまにうまく表示しない時があります。値は合ってるけど、桁数がめちゃ多くなる事があります。


MQL4に最初から入ってる関数なので、どういう処理なのか不明なんだけど、たぶん桁上りの時に上手く表示できないようです。









ご質問はコメント欄からお願いします