Posted by: Zeeshan Amjad | June 5, 2013

Creating Bollinger Band using Mindscape


Technical Analysis is an interesting sub field in finance, where we study the price patterns for forecasting purpose. It is also known as charting, because in this field with the help of charting we try to understand the price pattern. One interesting chart we are going to create now is Bollinger Band, introduced by John Bollinger and also trademarked by him.

Calculation of Bollinger band is very simple. It contains three parts, the simple moving average, upper band and lower band.

We can calculate the moving average of for any period, usually it is 20, but any suitable value can be uses.

The upper band is the sum of moving average and k times standard deviation and lower band is the moving average minus k times standard deviation.

If we represent simple moving average by SMA then the upper and lower band can be represent by these formulae.

Upper band = SMA + k * σ

Lower band = SMA – k * σ

Usually the value of k is 2, but any suitable value can be obtained.

Now the first step is to get the price data and perform these calculation. Here we are going to use the same technique we used while creating the overlay chart here.

After that we are going to create some auxiliary methods for our calculation.

Code Snippet
private double CalculateAverage(double[] data)
{
    int count = data.Length;
    double sum = 0;

    for (int i = 0; i < count; i++)
    {
        sum += data[i];
    }

    return sum / count;
}

private double CalculateVariance(double[] data)
{
    int count = data.Length;
    double sum = 0;
    double avg = CalculateAverage(data);

    for (int i = 0; i < count; i++)
    {
        sum += (data[i] – avg) * (data[i] – avg);
    }

    return sum / (count – 1);
}

private double CalculateSTDV(double[] data)
{
    double var = CalculateVariance(data);

    return Math.Sqrt(var);
}

 

We already created a class to store the data points of the chart.

Code Snippet
public class ChartData
{
    public double UpperBandData
    { get; set; }

    public double LowerBandData
    { get; set; }

    public double SMA
    { get; set; }
}

 

We have one class to not only store the chart data, but also get the input from the user interface and perform calculation accordingly. Here is a part of that class.

Code Snippet
public class BollingerBandData : INotifyPropertyChanged
{
    private ObservableCollection<int> _lowerBand;
    private ObservableCollection<int> _upperBand;
    private ObservableCollection<int> _movingAvg;
    private ObservableCollection<int> _length;
    private ObservableCollection<ChartData> _chartData;
    private int _selectedLowerBand;
    private int _selectedUpperBand;
    private int _selectedMovingAvg;
    private int _selectedLength;

    // other stuff
}

 

One we have all the basic stuff then calculating the data point is very easy. Here is a main calculation for the chart data.

Code Snippet
graphdata.ChartData.Clear();

int datalength = graphdata.SelectedMovingAverage + graphdata.SelectedLength;

for (int i = graphdata.SelectedLength – 1; i >= 0; i–)
{
    List<double> price = new List<double>();

    for (int j = 0; j < graphdata.SelectedMovingAverage; j++)
    {
        price.Add(data[i + j].Close);
    }

    double sma = CalculateAverage(price.ToArray());
    double sigma = CalculateSTDV(price.ToArray());
    double lower = sma – (graphdata.SelectedLowerBand * sigma);
    double upper = sma + (graphdata.SelectedUpperBand * sigma);

    graphdata.ChartData.Add(new ChartData() { SMA = sma, LowerBandData = lower, UpperBandData = upper });

 

In user interface, we give the user to select not only the value of upper and lower band constant, but also the period of moving average and how many total points we are going to consider. Here is complete XAML for our program.

Code Snippet
<Window x:Class="WpfBollingerBands.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
              xmlns:ms="clr-namespace:Mindscape.WpfElements.Charting;assembly=Mindscape.WpfElements"
        Title="Bollinger Bands" Height="400" Width="600">
    <Grid DataContext="{Binding}">
        <Grid.RowDefinitions>
            <RowDefinition Height="5*"/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
          <ms:Chart Margin="5" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="5"
                  Title="Bollinger Bands Microsoft Stock" DataContext="{Binding ChartData}">
            <ms:Chart.XAxis>
                <ms:ChartAxis Title="Time"/>
            </ms:Chart.XAxis>
            <ms:Chart.YAxis>
                <ms:ChartAxis Title="Price"/>
            </ms:Chart.YAxis>
            <ms:LineSeries ItemsSource="{Binding}"
                           SeriesBrush="Green"
                           YBinding="{Binding LowerBandData}" Title="Lower Band"/>
            <ms:LineSeries ItemsSource="{Binding}"
                           SeriesBrush="Blue"
                           YBinding="{Binding SMA}" Title="Moving Average"/>
            <ms:LineSeries ItemsSource="{Binding}"
                           SeriesBrush="Green"
                                       YBinding="{Binding UpperBandData}" Title="Upper Band"/>
        </ms:Chart>
        <TextBlock Grid.Column="0" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center">
            Upper band
        </TextBlock>
        <TextBlock Grid.Column="1" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center">
            Lower band
        </TextBlock>
        <TextBlock Grid.Column="2" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center">
            Moving Avg Window
        </TextBlock>
        <TextBlock Grid.Column="3" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center">
            Length
        </TextBlock>
        <ComboBox Margin="10" Grid.Column="0" Grid.Row="2" SelectedItem="{Binding SelectedUpperBand}"
                  ItemsSource="{Binding UpperBand}"/>
        <ComboBox Margin="10" Grid.Column="1" Grid.Row="2" SelectedItem="{Binding SelectedLowerBand}"
                  ItemsSource="{Binding UpperBand}"/>
        <ComboBox Margin="10" Grid.Column="2" Grid.Row="2" SelectedItem="{Binding SelectedMovingAverage}"
                  ItemsSource="{Binding MovingAverageWindow}"/>
        <ComboBox Margin="10" Grid.Column="3" Grid.Row="2" SelectedItem="{Binding SelectedLength}"
                          ItemsSource="{Binding Length}"/>
        <Button Margin="10" Grid.Column="4" Grid.Row="2" Click="Button_Click">Calculate</Button>
    </Grid>
</Window>

 

And here is complete C# code of the program.

Code Snippet
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Documents;

namespace WpfBollingerBands
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private BollingerBandData graphdata = new BollingerBandData();
        private List<TickerData> data = new List<TickerData>();

        public MainWindow()
        {
            InitializeComponent();

            string filename = @"C:\zamjad\Data\MSFT.csv";

            data = (from line in File.ReadAllLines(filename)
                        let tickerData = line.Split(',')
                        select new TickerData()
                        {
                            Date = Convert.ToDateTime(tickerData[0]),
                            Open = Convert.ToDouble(tickerData[1]),
                            High = Convert.ToDouble(tickerData[2]),
                            Low = Convert.ToDouble(tickerData[3]),
                            Close = Convert.ToDouble(tickerData[4]),
                            Volume = Convert.ToInt32(tickerData[5]),
                            AdjClose = Convert.ToDouble(tickerData[6])
                        }).ToList();

            graphdata.LowerBand.Add(1);
            graphdata.LowerBand.Add(2);
            graphdata.LowerBand.Add(3);
            graphdata.LowerBand.Add(1);

            graphdata.UpperBand.Add(1);
            graphdata.UpperBand.Add(2);
            graphdata.UpperBand.Add(3);
            graphdata.UpperBand.Add(4);

            graphdata.MovingAverageWindow.Add(10);
            graphdata.MovingAverageWindow.Add(20);
            graphdata.MovingAverageWindow.Add(40);
            graphdata.MovingAverageWindow.Add(50);

            graphdata.Length.Add(10);
            graphdata.Length.Add(30);
            graphdata.Length.Add(50);
            graphdata.Length.Add(100);

            DataContext = graphdata;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            graphdata.ChartData.Clear();

            int datalength = graphdata.SelectedMovingAverage + graphdata.SelectedLength;

            for (int i = graphdata.SelectedLength – 1; i >= 0; i–)
            {
                List<double> price = new List<double>();

                for (int j = 0; j < graphdata.SelectedMovingAverage; j++)
                {
                    price.Add(data[i + j].Close);
                }

                double sma = CalculateAverage(price.ToArray());
                double sigma = CalculateSTDV(price.ToArray());
                double lower = sma – (graphdata.SelectedLowerBand * sigma);
                double upper = sma + (graphdata.SelectedUpperBand * sigma);

                graphdata.ChartData.Add(new ChartData() { SMA = sma, LowerBandData = lower, UpperBandData = upper });
            }
        }

        private double CalculateAverage(double[] data)
        {
            int count = data.Length;
            double sum = 0;

            for (int i = 0; i < count; i++)
            {
                sum += data[i];
            }

            return sum / count;
        }

        private double CalculateVariance(double[] data)
        {
            int count = data.Length;
            double sum = 0;
            double avg = CalculateAverage(data);

            for (int i = 0; i < count; i++)
            {
                sum += (data[i] – avg) * (data[i] – avg);
            }

            return sum / (count – 1);
        }

        private double CalculateSTDV(double[] data)
        {
            double var = CalculateVariance(data);

            return Math.Sqrt(var);
        }
    }

    public class ChartData
    {
        public double UpperBandData
        { get; set; }

        public double LowerBandData
        { get; set; }

        public double SMA
        { get; set; }
    }

    public class BollingerBandData : INotifyPropertyChanged
    {
        private ObservableCollection<int> _lowerBand;
        private ObservableCollection<int> _upperBand;
        private ObservableCollection<int> _movingAvg;
        private ObservableCollection<int> _length;
        private ObservableCollection<ChartData> _chartData;
        private int _selectedLowerBand;
        private int _selectedUpperBand;
        private int _selectedMovingAvg;
        private int _selectedLength;

        public BollingerBandData()
        {
            _lowerBand = new ObservableCollection<int>();
            _upperBand = new ObservableCollection<int>();
            _movingAvg = new ObservableCollection<int>();
            _length = new ObservableCollection<int>();
            _chartData = new ObservableCollection<ChartData>();

            SelectedLowerBand = 2;
            SelectedUpperBand = 2;
            SelectedMovingAverage = 20;
            SelectedLength = 30;
        }

        public ObservableCollection<ChartData> ChartData
        {
            get
            {
                return _chartData;
            }
            set
            {
                _chartData = value;
                RaisePropertyChanged("ChartData");
            }
        }

        public ObservableCollection<int> LowerBand
        {
            get
            {
                return _lowerBand;
            }
            set
            {
                _lowerBand = value;
                RaisePropertyChanged("LowerBand");
            }
        }
        
        public ObservableCollection<int> UpperBand
        {
            get
            {
                return _upperBand;
            }
            set
            {
                _upperBand = value;
                RaisePropertyChanged("UpperBand");
            }
        }

        public ObservableCollection<int> MovingAverageWindow
        {
            get
            {
                return _movingAvg;
            }
            set
            {
                _movingAvg = value;
                RaisePropertyChanged("MovingAverageWindow");
            }
        }
        
        public ObservableCollection<int> Length
        {
            get
            {
                return _length;
            }
            set
            {
                _length = value;
                RaisePropertyChanged("Length");
            }
        }
        public int SelectedLowerBand
        {
            get
            {
                return _selectedLowerBand;
            }
            set
            {
                _selectedLowerBand = value;
                RaisePropertyChanged("SelectedLowerBand");
            }
        }

        public int SelectedUpperBand
        {
            get
            {
                return _selectedUpperBand;
            }
            set
            {
                _selectedUpperBand = value;
                RaisePropertyChanged("SelectedUpperBand");
            }
        }

        public int SelectedMovingAverage
        {
            get
            {
                return _selectedMovingAvg;
            }
            set
            {
                _selectedMovingAvg = value;
                RaisePropertyChanged("SelectedMovingAverage");
            }
        }

        public int SelectedLength
        {
            get
            {
                return _selectedLength;
            }
            set
            {
                _selectedLength = value;
                RaisePropertyChanged("SelectedLength");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = this.PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    public class TickerData
    {
        public DateTime Date
        { get; set; }

        public double Open
        { get; set; }

        public double High
        { get; set; }

        public double Low
        { get; set; }

        public double Close
        { get; set; }

        public int Volume
        { get; set; }

        public double AdjClose
        { get; set; }
    }
}

 

The default length is set to 30, but here is the output of the program with length of 100.

BollingerBand

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: