안녕하세요, 트레이더 여러분! 오늘은 메타트레이더 5에서 사용할 수 있는 커스텀 볼린저 밴드 지표에 대해 이야기해볼까 합니다. 기존의 볼린저 밴드는 단순 이동 평균 방법만 제공하지만, 제가 개발한 이 지표는 지수 이동 평균, 스무딩 이동 평균, 선형 가중 이동 평균 등 다양한 방법을 선택할 수 있는 옵션을 제공합니다.
지표를 사용하려면, 먼저 아래의 경로에 파일을 저장해야 합니다:
C:\Users\사용자이름\AppData\Roaming\MetaQuotes\Terminal\Indicators\Examples
추가된 기능은 다음과 같습니다:

기본값은 0으로 설정되어 있습니다:

여기서는 선형 가중 이동 평균을 선택하여 실행한 예시를 보여드리겠습니다:

다음은 지표의 코드입니다:
//+------------------------------------------------------------------+ //| BBPersonalizada.mq5 | //| Lucas Vidal | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Lucas Vidal" #property link "https://www.mql5.com/en/users/lucasmoura00" #property description "Bollinger Bands Personalizada" #include <MovingAverages.mqh> //--- #property indicator_chart_window #property indicator_buffers 4 #property indicator_plots 3 #property indicator_type1 DRAW_LINE #property indicator_color1 LightSeaGreen #property indicator_type2 DRAW_LINE #property indicator_color2 LightSeaGreen #property indicator_type3 DRAW_LINE #property indicator_color3 LightSeaGreen #property indicator_label1 "Bands middle" #property indicator_label2 "Bands upper" #property indicator_label3 "Bands lower" //--- input parameters enum MovingAverageMethod { Simple, // 0 Exponential, // 1 Smoothed, // 2 LinearWeighted // 3 }; input MovingAverageMethod InpMaMethod = Simple; // 이동 평균 방법 input int InpBandsPeriod=20; // 기간 input int InpBandsShift=0; // 이동 input double InpBandsDeviations=2.0 // 편차 //--- global variables int ExtBandsPeriod,ExtBandsShift; double ExtBandsDeviations; int ExtPlotBegin=0; //--- indicator buffer double ExtMLBuffer[]; double ExtTLBuffer[]; double ExtBLBuffer[]; double ExtStdDevBuffer[]; //+------------------------------------------------------------------+ //| 커스텀 지표 초기화 함수 | //+------------------------------------------------------------------+ void OnInit() { //--- 입력 값 확인 if(InpBandsPeriod<2) { ExtBandsPeriod=20; PrintFormat("잘못된 입력 변수 InpBandsPeriod=%d. 지표가 계산에 사용할 값=%d입니다.",InpBandsPeriod,ExtBandsPeriod); } else ExtBandsPeriod=InpBandsPeriod; if(InpBandsShift<0) { ExtBandsShift=0; PrintFormat("잘못된 입력 변수 InpBandsShift=%d. 지표가 계산에 사용할 값=%d입니다.",InpBandsShift,ExtBandsShift); } else ExtBandsShift=InpBandsShift; if(InpBandsDeviations==0.0) { ExtBandsDeviations=2.0; PrintFormat("잘못된 입력 변수 InpBandsDeviations=%f. 지표가 계산에 사용할 값=%f입니다.",InpBandsDeviations,ExtBandsDeviations); } else ExtBandsDeviations=InpBandsDeviations; //--- 버퍼 정의 SetIndexBuffer(0,ExtMLBuffer); SetIndexBuffer(1,ExtTLBuffer); SetIndexBuffer(2,ExtBLBuffer); SetIndexBuffer(3,ExtStdDevBuffer,INDICATOR_CALCULATIONS); //--- 인덱스 레이블 설정 PlotIndexSetString(0,PLOT_LABEL,"Bands("+string(ExtBandsPeriod)+") Middle"); PlotIndexSetString(1,PLOT_LABEL,"Bands("+string(ExtBandsPeriod)+") Upper"); PlotIndexSetString(2,PLOT_LABEL,"Bands("+string(ExtBandsPeriod)+") Lower"); //--- 지표 이름 설정 IndicatorSetString(INDICATOR_SHORTNAME,"Bollinger Bands"); //--- 인덱스 그리기 시작 설정 ExtPlotBegin=ExtBandsPeriod-1; PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtBandsPeriod); PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,ExtBandsPeriod); PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,ExtBandsPeriod); //--- 인덱스 이동 설정 PlotIndexSetInteger(0,PLOT_SHIFT,ExtBandsShift); PlotIndexSetInteger(1,PLOT_SHIFT,ExtBandsShift); PlotIndexSetInteger(2,PLOT_SHIFT,ExtBandsShift); //--- 지표 값의 숫자 자리수 설정 IndicatorSetInteger(INDICATOR_DIGITS,_Digits+1); } //+------------------------------------------------------------------+ //| 이동 평균 계산 | //+------------------------------------------------------------------+ double CalculateMovingAverage(int position, int period, const double &price[]) { switch(InpMaMethod) { case Simple: return SimpleMA(position, period, price); case Exponential: // iMA 호출 시 올바른 매개변수 수정 return iMA(NULL, 0, period, 0, MODE_EMA, PRICE_CLOSE); case Smoothed: // SMMA 함수를 구현하세요 break; case LinearWeighted: return LinearWeightedMA(position, period, price); } return 0; // 정의되지 않은 방법의 기본 반환 } //+------------------------------------------------------------------+ //| 볼린저 밴드 | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { if(rates_total<ExtPlotBegin) return(0); //--- 이전 시작 시점으로 인덱스 그리기 시작 설정 if(ExtPlotBegin!=ExtBandsPeriod+begin) { ExtPlotBegin=ExtBandsPeriod+begin; PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,ExtPlotBegin); PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,ExtPlotBegin); PlotIndexSetInteger(2,PLOT_DRAW_BEGIN,ExtPlotBegin); } //--- 계산 시작 int pos; if(prev_calculated>1) pos=prev_calculated-1; else pos=0; //--- 메인 사이클 for(int i=pos; i<rates_total && !IsStopped(); i++) { //--- 중간선 ExtMLBuffer[i]=CalculateMovingAverage(i, ExtBandsPeriod, price); //--- 표준편차 계산 및 기록 ExtStdDevBuffer[i]=StdDev_Func(i,price,ExtMLBuffer,ExtBandsPeriod); //--- 상한선 ExtTLBuffer[i]=ExtMLBuffer[i]+ExtBandsDeviations*ExtStdDevBuffer[i]; //--- 하한선 ExtBLBuffer[i]=ExtMLBuffer[i]-ExtBandsDeviations*ExtStdDevBuffer[i]; } //--- OnCalculate 완료. 새로운 prev_calculated 반환. return(rates_total); } //+------------------------------------------------------------------+ //| 표준 편차 계산 | //+------------------------------------------------------------------+ double StdDev_Func(const int position,const double &price[],const double &ma_price[],const int period) { double std_dev=0.0; //--- 표준편차 계산 if(position>=period) { for(int i=0; i<period; i++) std_dev+=MathPow(price[position-i]-ma_price[position],2.0); std_dev=MathSqrt(std_dev/period); } //--- 계산된 값 반환 return(std_dev); } //+------------------------------------------------------------------+