custom_bands

Download script
Author: 2005-2014, MetaQuotes Software Corp.
custom_bands

This custom technical indicator is designed to help traders visualize price volatility and identify potential overbought or oversold conditions on a trading chart. It functions by calculating three distinct lines: a central moving average and two outer "bands" that expand or contract based on market activity.

Core Logic Overview

The script operates by processing historical price data to determine the general trend of an asset while simultaneously measuring how much that price fluctuates around that trend.

1. Data Input Selection Before performing any calculations, the script identifies which specific price point it should track. Depending on your preference, it can monitor the opening price, closing price, highest price, lowest price, or various weighted averages of these values (such as a "Typical" or "Weighted" price).

2. The Middle Line (Trend Basis) The center of the indicator is a Moving Average. This represents the "heartbeat" of the current trend. The script offers several different mathematical methods to calculate this average, allowing you to choose between:

  • Simple averages (equal weight for all periods)
  • Exponential/Smoothed averages (giving more importance to recent data)
  • Linear weighted averages

3. Volatility Measurement (Standard Deviation) To create the outer bands, the script calculates the "Standard Deviation." In non-technical terms, this is a measure of how much the price "wiggles" or deviates from the middle moving average. If the price stays very close to the average, the deviation is low; if the price swings wildly, the deviation is high.

4. The Outer Bands (Upper and Lower) The final visual components are the Upper and Lower bands. These are calculated by taking the middle moving average and adding or subtracting a specific multiple of the Standard Deviation.

  • The Upper Band: Represents the "ceiling" of normal price action.
  • The Lower Band: Represents the "floor" of normal price action.

How It Works in Practice

By combining these elements, the indicator creates a visual "channel." When market volatility is low, the bands tighten together. When the market becomes erratic or volatile, the bands widen significantly. Traders use this logic to see when the price has pushed too far away from its average (hitting the ceiling or floor), which may suggest that the current move is overextended and a reversal or consolidation might occur.

Miscellaneous
Implements a curve of type %1
3 Views
1 Downloads
0 Favorites
custom_bands
//+------------------------------------------------------------------+
//|                                                 Custom Bands.mq4 |
//|                   Copyright 2005-2015, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright   "2005-2014, MetaQuotes Software Corp."
#property link        "https://www.mql5.com"
#property description "Bollinger Bands with customizable moving average method and applied price"
#property strict

#include <MovingAverages.mqh>

#property indicator_chart_window
#property indicator_buffers 3
#property indicator_color1 Red
#property indicator_color2 Red
#property indicator_color3 Red
//--- indicator parameters
input ENUM_MA_METHOD InpMovingMethod=MODE_SMA;   // Moving Average Method
input ENUM_APPLIED_PRICE InpAppliedPrice=PRICE_CLOSE;   // Applied Price
input int    InpBandsPeriod=20;      // Bands Period
input int    InpBandsShift=0;        // Bands Shift
input double InpBandsDeviations=2.0; // Bands Deviations
//--- buffers
double ExtMovingBuffer[];
double ExtUpperBuffer[];
double ExtLowerBuffer[];
double ExtStdDevBuffer[];
double ExtPriceBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//--- 1 additional buffer used for counting
   IndicatorBuffers(5);
   IndicatorDigits(Digits);
//--- middle line
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,ExtMovingBuffer);
   SetIndexShift(0,InpBandsShift);
   SetIndexLabel(0,"Bands MA");
//--- upper band
   SetIndexStyle(1,DRAW_LINE);
   SetIndexBuffer(1,ExtUpperBuffer);
   SetIndexShift(1,InpBandsShift);
   SetIndexLabel(1,"Bands Upper");
//--- lower band
   SetIndexStyle(2,DRAW_LINE);
   SetIndexBuffer(2,ExtLowerBuffer);
   SetIndexShift(2,InpBandsShift);
   SetIndexLabel(2,"Bands Lower");
//--- work buffer
   SetIndexBuffer(3,ExtStdDevBuffer);
   SetIndexBuffer(4,ExtPriceBuffer);
//--- 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);
//--- initialization done
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Bollinger Bands                                                  |
//+------------------------------------------------------------------+
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[])
  {
   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(ExtPriceBuffer,false);
   ArraySetAsSeries(close,false);
   ArraySetAsSeries(open,false);
   ArraySetAsSeries(high,false);
   ArraySetAsSeries(low,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;
        }
     }
//--- starting calculation
   if(prev_calculated>1)
      pos=prev_calculated-1;
   else
      pos=0;
//--- main cycle
   for(i=pos; i<rates_total && !IsStopped(); i++)
     {
      //--- price buffer
      switch(InpAppliedPrice)
        {
         case PRICE_CLOSE:
            ExtPriceBuffer[i]=close[i];
            break;
         case PRICE_OPEN:
            ExtPriceBuffer[i]=open[i];
            break;
         case PRICE_HIGH:
            ExtPriceBuffer[i]=high[i];
            break;
         case PRICE_LOW:
            ExtPriceBuffer[i]=low[i];
            break;
         case PRICE_MEDIAN:
            ExtPriceBuffer[i]=(high[i]+low[i])/2;
            break;
         case PRICE_TYPICAL:
         	ExtPriceBuffer[i]=(high[i]+low[i]+close[i])/3;
            break;
         case PRICE_WEIGHTED:
            ExtPriceBuffer[i]=(high[i]+low[i]+close[i]*2)/4;
            break;
        }
      //--- middle line
      switch(InpMovingMethod)
        {
         //--- Simple
         case  MODE_SMA:
            ExtMovingBuffer[i]=SimpleMA(i,InpBandsPeriod,ExtPriceBuffer);
            break;
            //--- Exponential
         case MODE_EMA:
            if(i==0)
            ExtMovingBuffer[i]=SimpleMA(i,InpBandsPeriod,ExtPriceBuffer);
            else
               ExtMovingBuffer[i]=ExponentialMA(i,InpBandsPeriod,ExtMovingBuffer[i-1],ExtPriceBuffer);
            break;
            //--- Smooted
         case MODE_SMMA:
            if(i==0)
            ExtMovingBuffer[i]=SimpleMA(i,InpBandsPeriod,ExtPriceBuffer);
            else
               ExtMovingBuffer[i]=SmoothedMA(i,InpBandsPeriod,ExtMovingBuffer[i-1],ExtPriceBuffer);
            break;
            break;
            //--- Linear Weighted
         case MODE_LWMA:
            ExtMovingBuffer[i]=LinearWeightedMA(i,InpBandsPeriod,ExtPriceBuffer);
            break;
         default:
            break;
        }
      //--- calculate and write down StdDev
      ExtStdDevBuffer[i]=StdDev_Func(i,ExtPriceBuffer,ExtMovingBuffer,InpBandsPeriod);
      //--- upper line
      ExtUpperBuffer[i]=ExtMovingBuffer[i]+InpBandsDeviations*ExtStdDevBuffer[i];
      //--- lower line
      ExtLowerBuffer[i]=ExtMovingBuffer[i]-InpBandsDeviations*ExtStdDevBuffer[i];
      //---
     }
//---- OnCalculate done. Return new prev_calculated.
   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);
  }
//+------------------------------------------------------------------+

Comments