/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ namespace QuantConnect.Indicators { /// /// This indicator creates a moving average (middle band) with an upper band and lower band /// fixed at k standard deviations above and below the moving average. /// public class BollingerBands : Indicator, IIndicatorWarmUpPeriodProvider { /// /// Gets the type of moving average /// public MovingAverageType MovingAverageType { get; } /// /// Gets the standard deviation /// public IndicatorBase StandardDeviation { get; } /// /// Gets the middle Bollinger band (moving average) /// public IndicatorBase MiddleBand { get; } /// /// Gets the upper Bollinger band (middleBand + k * stdDev) /// public IndicatorBase UpperBand { get; } /// /// Gets the lower Bollinger band (middleBand - k * stdDev) /// public IndicatorBase LowerBand { get; } /// /// Gets the Bollinger BandWidth indicator /// BandWidth = ((Upper Band - Lower Band) / Middle Band) * 100 /// public IndicatorBase BandWidth { get; } /// /// Gets the Bollinger %B /// %B = (Price - Lower Band)/(Upper Band - Lower Band) /// public IndicatorBase PercentB { get; } /// /// Gets the Price level /// public IndicatorBase Price { get; } /// /// Initializes a new instance of the BollingerBands class /// /// The period of the standard deviation and moving average (middle band) /// The number of standard deviations specifying the distance between the middle band and upper or lower bands /// The type of moving average to be used public BollingerBands(int period, decimal k, MovingAverageType movingAverageType = MovingAverageType.Simple) : this($"BB({period},{k})", period, k, movingAverageType) { } /// /// Initializes a new instance of the BollingerBands class /// /// The name of this indicator /// The period of the standard deviation and moving average (middle band) /// The number of standard deviations specifying the distance between the middle band and upper or lower bands /// The type of moving average to be used public BollingerBands(string name, int period, decimal k, MovingAverageType movingAverageType = MovingAverageType.Simple) : base(name) { WarmUpPeriod = period; MovingAverageType = movingAverageType; StandardDeviation = new StandardDeviation(name + "_StandardDeviation", period); MiddleBand = movingAverageType.AsIndicator(name + "_MiddleBand", period); LowerBand = MiddleBand.Minus(StandardDeviation.Times(k), name + "_LowerBand"); UpperBand = MiddleBand.Plus(StandardDeviation.Times(k), name + "_UpperBand"); var UpperMinusLower = UpperBand.Minus(LowerBand); BandWidth = UpperMinusLower .Over(MiddleBand) .Times(new ConstantIndicator("ct", 100m), name + "_BandWidth"); Price = new Identity(name + "_Close"); PercentB = IndicatorExtensions.Over( Price.Minus(LowerBand), UpperMinusLower, name + "_%B"); } /// /// Gets a flag indicating when this indicator is ready and fully initialized /// public override bool IsReady => MiddleBand.IsReady && UpperBand.IsReady && LowerBand.IsReady && BandWidth.IsReady && PercentB.IsReady; /// /// Required period, in data points, for the indicator to be ready and fully initialized. /// public int WarmUpPeriod { get; } /// /// Computes the next value of the following sub-indicators from the given state: /// StandardDeviation, MiddleBand, UpperBand, LowerBand, BandWidth, %B /// /// The input given to the indicator /// The input is returned unmodified. protected override decimal ComputeNextValue(IndicatorDataPoint input) { StandardDeviation.Update(input); MiddleBand.Update(input); Price.Update(input); return input.Value; } /// /// Validate and Compute the next value for this indicator /// /// Input for this indicator /// of this update /// Override implemented to handle GH issue #4927 protected override IndicatorResult ValidateAndComputeNextValue(IndicatorDataPoint input) { // Update our Indicators var value = ComputeNextValue(input); // If the STD = 0, we know that the our PercentB indicator will fail to update. This is // because the denominator will be 0. When this is the case after fully ready we do not // want the BollingerBands to emit an update because its PercentB property will be stale. return IsReady && StandardDeviation.Current.Value == 0 ? new IndicatorResult(value, IndicatorStatus.MathError) : new IndicatorResult(value); } /// /// Resets this indicator and all sub-indicators (StandardDeviation, LowerBand, MiddleBand, UpperBand, BandWidth, %B) /// public override void Reset() { StandardDeviation.Reset(); MiddleBand.Reset(); UpperBand.Reset(); LowerBand.Reset(); BandWidth.Reset(); PercentB.Reset(); base.Reset(); } } }