/// <summary> /// Computes the next value in the transform. /// value1 is a function used to normalize price withing the last _period day range. /// value1 is centered on its midpoint and then doubled so that value1 will swing between -1 and +1. /// value1 is also smoothed with an exponential moving average whose alpha is 0.33. /// /// Since the smoothing may allow value1 to exceed the _period day price range, limits are introduced to /// preclude the transform from blowing up by having an input larger than unity. /// </summary> /// <param name="input">IndicatorDataPoint - the time and value of the next price</param> /// <returns></returns> protected override decimal ComputeNextValue(DataPointBar input) { var x = 0.0; var y = 0.0; var price = (input.Low + input.High) / 2m; _medianMin.Update(input.Occured, input.TimeZone, price); _medianMax.Update(input.Occured, input.TimeZone, price); if (!IsReady) { return(0); } var minL = _medianMin.Current.Price; var maxH = _medianMax.Current.Price; if (minL != maxH) { x = _alpha * 2 * ((double)((price - minL) / (maxH - minL)) - .5) + (1 - _alpha) * _previous; y = FisherTransformFunction(x); } _previous = x; return(Convert.ToDecimal(y) + .5m * Current.Price); }
/// <summary> /// Computes the Slow Stochastic %K. /// </summary> /// <param name="period">The period.</param> /// <param name="constantK">The constant k.</param> /// <param name="input">The input.</param> /// <returns>The Slow Stochastics %K value.</returns> private decimal ComputeStochK(int period, int constantK, DataPointBar input) { var stochK = _maximum.Samples >= (period + constantK - 1) ? _sumFastK / constantK : new decimal(0.0); _sumSlowK.Update(input.Occured, input.TimeZone, stochK); return(stochK * 100); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(DataPointBar input) { AroonUp.Update(input.Occured, input.TimeZone, input.High); AroonDown.Update(input.Occured, input.TimeZone, input.Low); return(AroonUp - AroonDown); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(DataPointBar input) { if (!IsReady) { _previousInput = input; return(0m); } var greatest = input.High - input.Low; var value2 = Math.Abs(_previousInput.Close - input.High); if (value2 > greatest) { greatest = value2; } var value3 = Math.Abs(_previousInput.Close - input.Low); if (value3 > greatest) { greatest = value3; } _previousInput = input; return(greatest); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The trade bar input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(DataPointBar input) { // On first iteration we can’t produce an SAR value so we save the current bar and return zero if (Samples == 1) { _previousBar = input; // return a value that's close to where we will be, returning 0 doesn't make sense return(input.Close); } // On second iteration we initiate the position the extreme point and the SAR if (Samples == 2) { Init(input); _previousBar = input; return(_sar); } if (_isLong) { HandleLongPosition(input); } else { HandleShortPosition(input); } _previousBar = input; return(_outputSar); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(DataPointBar input) { _adx.Update(input); _adxHistory.Add(_adx); return((_adx + _adxHistory[Math.Min(_adxHistory.Count - 1, _period - 1)]) / 2); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(DataPointBar input) { _trueRange.Update(input); if (Samples == 1) { _previousInput = input; return(50m); } var buyingPressure = new IndicatorDataPoint { Price = input.Close - Math.Min(input.Low, _previousInput.Close) }; _sumBuyingPressure1.Update(buyingPressure); _sumBuyingPressure2.Update(buyingPressure); _sumBuyingPressure3.Update(buyingPressure); _sumTrueRange1.Update(_trueRange.Current); _sumTrueRange2.Update(_trueRange.Current); _sumTrueRange3.Update(_trueRange.Current); _previousInput = input; if (!IsReady) { return(50m); } var average1 = _sumBuyingPressure1 / _sumTrueRange1; var average2 = _sumBuyingPressure2 / _sumTrueRange2; var average3 = _sumBuyingPressure3 / _sumTrueRange3; return(100m * (4 * average1 + 2 * average2 + average3) / 7); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(DataPointBar input) { // compute the true range and then send it to our smoother TrueRange.Update(input); _smoother.Update(input.Occured, input.TimeZone, TrueRange); return(_smoother.Current.Price); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> protected override decimal ComputeNextValue(DataPointBar input) { _maximum.Update(input.Occured, input.TimeZone, input.High); _mininum.Update(input.Occured, input.TimeZone, input.Low); FastStoch.Update(input); StochK.Update(input); StochD.Update(input); return(FastStoch); }
/// <summary> /// Computes the average value /// </summary> /// <param name="input">The data for the calculation</param> /// <returns>The average value</returns> protected override decimal ComputeNextValue(DataPointBar input) { var price = (double)(input.High + input.Low) / 2; _high.Add((double)input.High); _low.Add((double)input.Low); // our first data point just return identity if (_high.Samples <= _high.Size) { _filt = price; } double n1; double n2; double n3; double hh; double ll; double dimen = 0; double alpha; n3 = (_high.Max() - _low.Min()) / _n; hh = _high.Take(_n / 2).Max(); ll = _low.Take(_n / 2).Min(); n1 = (hh - ll) / (_n / 2); if (_high.IsReady) { hh = _high.Skip(_n / 2).Take(_n / 2).Max(); ll = _low.Skip(_n / 2).Take(_n / 2).Min(); } n2 = (hh - ll) / (_n / 2); if (n1 > 0 && n2 > 0 && n3 > 0) { dimen = (Math.Log(n1 + n2) - Math.Log(n3)) / Math.Log(2); } ; alpha = Math.Exp(_w * (dimen - 1)); if (alpha < .01) { alpha = .01; } if (alpha > 1) { alpha = 1; } _filt = alpha * price + (1 - alpha) * _filt; return((decimal)_filt); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator, which by convention is the mean value of the upper band and lower band.</returns> protected override decimal ComputeNextValue(DataPointBar input) { if (_previousInput != null) { UpperBand.Update(new IndicatorDataPoint(_previousInput.Occured, _previousInput.TimeZone, _previousInput.High)); LowerBand.Update(new IndicatorDataPoint(_previousInput.Occured, _previousInput.TimeZone, _previousInput.Low)); } _previousInput = input; return (UpperBand.Current.Price + LowerBand.Current.Price) / 2; }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(DataPointBar input) { _maximum.Update(new IndicatorDataPoint { Price = input.High }); _minimum.Update(new IndicatorDataPoint { Price = input.Low }); return((_maximum + _minimum) / 2); }
/// <summary> /// Resets this indicator to its initial state /// </summary> public override void Reset() { _previousInput = null; _trueRange.Reset(); _sumBuyingPressure1.Reset(); _sumBuyingPressure2.Reset(); _sumBuyingPressure3.Reset(); _sumTrueRange1.Reset(); _sumTrueRange2.Reset(); _sumTrueRange3.Reset(); base.Reset(); }
/// <summary> /// Computes the True Range value. /// </summary> /// <param name="input">The input.</param> /// <returns></returns> private decimal ComputeTrueRange(DataPointBar input) { var trueRange = new decimal(0.0); if (_previousInput == null) { return(trueRange); } trueRange = (Math.Max(Math.Abs(input.Low - _previousInput.Close), Math.Max(TrueRange.Current, Math.Abs(input.High - _previousInput.Close)))); return(trueRange); }
/// <summary> /// Resets this indicator to its initial state /// </summary> public override void Reset() { base.Reset(); _previousInput = null; TrueRange.Reset(); DirectionalMovementPlus.Reset(); DirectionalMovementMinus.Reset(); SmoothedTrueRange.Reset(); SmoothedDirectionalMovementMinus.Reset(); SmoothedDirectionalMovementPlus.Reset(); PositiveDirectionalIndex.Reset(); NegativeDirectionalIndex.Reset(); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(DataPointBar input) { Minimum.Update(input.Occured, input.TimeZone, input.Low); Maximum.Update(input.Occured, input.TimeZone, input.High); if (!IsReady) { return(0); } var range = (Maximum.Current.Price - Minimum.Current.Price); return(range == 0 ? 0 : -100m * (Maximum.Current.Price - input.Close) / range); }
/// <summary> /// Computes the TrueRange from the current and previous trade bars /// /// TrueRange is defined as the maximum of the following: /// High - Low /// ABS(High - PreviousClose) /// ABS(Low - PreviousClose) /// </summary> /// <param name="previous">The previous trade bar</param> /// <param name="current">The current trade bar</param> /// <returns>The true range</returns> public static decimal ComputeTrueRange(DataPointBar previous, DataPointBar current) { var range1 = current.High - current.Low; if (previous == null) { return(range1); } var range2 = Math.Abs(current.High - previous.Close); var range3 = Math.Abs(current.Low - previous.Close); return(Math.Max(range1, Math.Max(range2, range3))); }
/// <summary> /// Computes the next value for this indicator from the given state. /// </summary> /// <param name="input">The TradeBar to this indicator on this time step</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(DataPointBar input) { AverageTrueRange.Update(input); var typicalPrice = (input.High + input.Low + input.Close) / 3m; MiddleBand.Update(input.Occured, input.TimeZone, typicalPrice); // poke the upper/lower bands, they actually don't use the input, they compute // based on the ATR and the middle band LowerBand.Update(input); UpperBand.Update(input); return(MiddleBand); }
/// <summary> /// Initialize the indicator values /// </summary> private void Init(DataPointBar currentBar) { // init position _isLong = currentBar.Close >= _previousBar.Close; // init sar and Extreme price if (_isLong) { _ep = Math.Min(currentBar.High, _previousBar.High); _sar = _previousBar.Low; } else { _ep = Math.Min(currentBar.Low, _previousBar.Low); _sar = _previousBar.High; } }
/// <summary> /// Creates a new AverageTrueRange indicator using the specified period and moving average type /// </summary> /// <param name="name">The name of this indicator</param> /// <param name="period">The smoothing period used to smooth the true range values</param> /// <param name="movingAverageType">The type of smoothing used to smooth the true range values</param> public AverageTrueRange(string name, int period, MovingAverageType movingAverageType = MovingAverageType.Wilders) : base(name) { _smoother = movingAverageType.AsIndicator(string.Format("{0}_{1}", name, movingAverageType), period); DataPointBar previous = null; TrueRange = new FunctionalIndicator <DataPointBar>(name + "_TrueRange", currentBar => { // in our ComputeNextValue function we'll just call the ComputeTrueRange var nextValue = ComputeTrueRange(previous, currentBar); previous = currentBar; return(nextValue); } // in our IsReady function we just need at least one sample , trueRangeIndicator => trueRangeIndicator.Samples >= 1 ); }
/// <summary> /// Computes the Fast Stochastic %K. /// </summary> /// <param name="period">The period.</param> /// <param name="input">The input.</param> /// <returns>The Fast Stochastics %K value.</returns> private decimal ComputeFastStoch(int period, DataPointBar input) { var denominator = (_maximum - _mininum); var numerator = (input.Close - _mininum); decimal fastStoch; if (denominator == 0m) { // if there's no range, just return constant zero fastStoch = 0m; } else { fastStoch = _maximum.Samples >= period ? numerator / denominator : new decimal(0.0); } _sumFastK.Update(input.Occured, input.TimeZone, fastStoch); return(fastStoch * 100); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(DataPointBar input) { decimal typicalPrice = (input.High + input.Low + input.Close) / 3.0m; TypicalPriceAverage.Update(input.Occured, input.TimeZone, typicalPrice); TypicalPriceMeanDeviation.Update(input.Occured, input.TimeZone, typicalPrice); // compare this to zero, since if the mean deviation is very small we can get // precision errors due to non-floating point math var weightedMeanDeviation = _k * TypicalPriceMeanDeviation.Current; if (weightedMeanDeviation == 0.0m) { return(0.0m); } return((typicalPrice - TypicalPriceAverage.Current) / weightedMeanDeviation); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> protected override decimal ComputeNextValue(DataPointBar input) { TenkanMaximum.Update(input.Occured, input.TimeZone, input.High); TenkanMinimum.Update(input.Occured, input.TimeZone, input.Low); Tenkan.Update(input); KijunMaximum.Update(input.Occured, input.TimeZone, input.High); KijunMinimum.Update(input.Occured, input.TimeZone, input.Low); Kijun.Update(input); DelayedTenkanSenkouA.Update(input.Occured, input.TimeZone, Tenkan.Current.Price); DelayedKijunSenkouA.Update(input.Occured, input.TimeZone, Kijun.Current.Price); SenkouA.Update(input); SenkouBMaximum.Update(input.Occured, input.TimeZone, input.High); SenkouBMinimum.Update(input.Occured, input.TimeZone, input.Low); DelayedMaximumSenkouB.Update(input.Occured, input.TimeZone, SenkouBMaximum.Current.Price); DelayedMinimumSenkouB.Update(input.Occured, input.TimeZone, SenkouBMinimum.Current.Price); SenkouB.Update(input); return(input.Close); }
/// <summary> /// Computes the positive directional movement. /// </summary> /// <param name="input">The input.</param> /// <returns></returns> private decimal ComputePositiveDirectionalMovement(DataPointBar input) { var postiveDirectionalMovement = new decimal(0.0); if (_previousInput == null) { return(postiveDirectionalMovement); } if ((input.High - _previousInput.High) >= (_previousInput.Low - input.Low)) { if ((input.High - _previousInput.High) > 0) { postiveDirectionalMovement = input.High - _previousInput.High; } } return(postiveDirectionalMovement); }
/// <summary> /// Computes the negative directional movement. /// </summary> /// <param name="input">The input.</param> /// <returns></returns> private decimal ComputeNegativeDirectionalMovement(DataPointBar input) { var negativeDirectionalMovement = new decimal(0.0); if (_previousInput == null) { return(negativeDirectionalMovement); } if ((_previousInput.Low - input.Low) > (input.High - _previousInput.High)) { if ((_previousInput.Low - input.Low) > 0) { negativeDirectionalMovement = _previousInput.Low - input.Low; } } return(negativeDirectionalMovement); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(DataPointBar input) { TrueRange.Update(input); DirectionalMovementPlus.Update(input); DirectionalMovementMinus.Update(input); SmoothedTrueRange.Update(Current); SmoothedDirectionalMovementMinus.Update(Current); SmoothedDirectionalMovementPlus.Update(Current); if (_previousInput != null) { PositiveDirectionalIndex.Update(Current); NegativeDirectionalIndex.Update(Current); } var diff = Math.Abs(PositiveDirectionalIndex - NegativeDirectionalIndex); var sum = PositiveDirectionalIndex + NegativeDirectionalIndex; var value = sum == 0 ? 50 : ((_period - 1) * Current.Price + 100 * diff / sum) / _period; _previousInput = input; return(value); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(DataPointBar input) { _tr.Update(input); if (!IsReady) { _atr.Update(input); return(input.Close != 0 ? _atr / input.Close * 100 : 0m); } if (Samples == _period + 1) { // first output value is SMA of TrueRange _atr.Update(input); _lastAtrValue = _atr; } else { // next TrueRange values are smoothed using Wilder's approach _lastAtrValue = (_lastAtrValue * (_period - 1) + _tr) / _period; } return(input.Close != 0 ? _lastAtrValue / input.Close * 100 : 0m); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="window">The window of data held in this indicator</param> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(IReadOnlyWindow <DataPointBar> window, DataPointBar input) { if (!IsReady) { if (Samples >= Period - _bodyLongAveragePeriod - 1 && Samples < Period - 1) { _bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input); } if (Samples >= Period - _bodyShortAveragePeriod) { _bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input); } return(0m); } decimal value; if ( // 1st: long GetRealBody(window[1]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[1]) && // 2nd: short GetRealBody(input) <= GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) && // engulfed by 1st Math.Max(input.Close, input.Open) < Math.Max(window[1].Close, window[1].Open) && Math.Min(input.Close, input.Open) > Math.Min(window[1].Close, window[1].Open) ) { value = -(int)GetCandleColor(window[1]); } else { value = 0m; } // add the current range and subtract the first range: this is done after the pattern recognition // when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle) _bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[1]) - GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 1]); _bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) - GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]); return(value); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="window">The window of data held in this indicator</param> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(IReadOnlyWindow <DataPointBar> window, DataPointBar input) { if (!IsReady) { if (Samples >= Period - _bodyShortAveragePeriod) { _bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input); } if (Samples >= Period - _shadowLongAveragePeriod) { _shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, input); } if (Samples >= Period - _shadowVeryShortAveragePeriod) { _shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input); } return(0m); } decimal value; if ( // small rb GetRealBody(input) < GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) && // long upper shadow GetUpperShadow(input) > GetCandleAverage(CandleSettingType.ShadowLong, _shadowLongPeriodTotal, input) && // very short lower shadow GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input) && // gap up GetRealBodyGapUp(input, window[1]) ) { value = -1m; } else { value = 0m; } // add the current range and subtract the first range: this is done after the pattern recognition // when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle) _bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) - GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]); _shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, input) - GetCandleRange(CandleSettingType.ShadowLong, window[_shadowLongAveragePeriod]); _shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input) - GetCandleRange(CandleSettingType.ShadowVeryShort, window[_shadowVeryShortAveragePeriod]); return(value); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="window">The window of data held in this indicator</param> /// <param name="input">The input given to the indicator</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(IReadOnlyWindow <DataPointBar> window, DataPointBar input) { if (!IsReady) { if (Samples >= Period - _bodyDojiAveragePeriod) { _bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input); } return(0m); } var value = GetRealBody(input) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, input) ? 1m : 0m; // add the current range and subtract the first range: this is done after the pattern recognition // when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle) _bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input) - GetCandleRange(CandleSettingType.BodyDoji, window[_bodyDojiAveragePeriod]); return(value); }