BollingerBand.cs // Copyright (C) 2002-2005 Competo Solutions, Inc.
// All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR
// FITNESS FOR A PARTICULAR PURPOSE.

using System;

using Trader.Data;

namespace Trader.Study {
        /// <summary>
        /// Represents a Bollinger Band indicator.
        /// </summary>
        public class BollingerBand : Indicator {
                private SMA sma;
                private StdDev stdDev;
                private double middle;
                private double upper;
                private double lower;
                private int period;
                private int range;

                /// <summary>
                /// ctor.
                /// </summary>
                /// <remarks>
                /// Default: Period = 20 and Range = 2 sigma
                /// </remarks>
                public BollingerBand()  :  base("Bollinger Band")                {
                        this.period = 20;
                        this.range = 2;
                        this.sma = new SMA(20);
                        this.stdDev = new StdDev(20);
                        base.Position = ChartPosition.Upper;
                }

                /// <summary>
                /// ctor.
                /// </summary>
                public BollingerBand(int period, int range)  :  base("Bollinger Band")                {
                        this.period = period;
                        this.range = range;
                        this.sma = new SMA(period);
                        this.stdDev = new StdDev(period);
                        base.Position = ChartPosition.Upper;
                }

                /// <summary>
                /// Gets or sets the period.
                /// </summary>
                [IndicatorParameter]
                public int Period {
                        get {
                                return this.period;
                        }
                        set {
                                this.period = value;
                                this.sma.Period = value;
                                this.stdDev.Period = value;
                        }
                }

                /// <summary>
                /// Gets or sets the range.
                /// </summary>
                [IndicatorParameter]
                public int Range {
                        get {
                                return this.range;
                        }
                        set {
                                this.range = value;
                        }
                }

                /// <summary>
                /// Calculates the sma at index.
                /// </summary>
                /// <remarks>
                /// After each calculation, the result is in Upper, Lower and Middle
                /// properties. The return value here is the middle.
                /// </remarks>
                /// <param name="index"></param>
                /// <param name="series"></param>
                public override double Calculate(int index, Series series) {
                        if (index == 0) {
                                base.Maximum = 0;
                                base.Minimum = 0;
                        }

      double sigma = series.Accept(index, this.stdDev);
                        this.middle = series.Accept(index, this.sma);
                        this.upper = this.middle + sigma*this.range;
                        this.lower = this.middle - sigma*this.range;

                        return this.middle;
                }

                /// <summary>
                /// Gets the upper band.
                /// </summary>
                [IndicatorValue]
                public double Upper {
                        get {
                                return this.upper;
                        }
                }

                /// <summary>
                /// Gets the middle line.
                /// </summary>
                [IndicatorValue]
                public double Middle {
                        get {
                                return this.middle;
                        }
                }

                /// <summary>
                /// Gets the lower band.
                /// </summary>
                [IndicatorValue]
                public double Lower {
                        get {
                                return this.lower;
                        }
                }

                /// <summary>
                /// Gets the sigma.
                /// </summary>
                public double Sigma {
                        get {
                                return this.stdDev.Sigma;
                        }
                }
        }
}