/// <summary> /// Configures the event handlers for Left.Updated and Right.Updated to update this instance when /// they both have new data. /// </summary> private void ConfigureEventHandlers() { // if either of these are constants then there's no reason bool leftIsConstant = Left.GetType().IsSubclassOfGeneric(typeof(ConstantIndicator <>)); bool rightIsConstant = Right.GetType().IsSubclassOfGeneric(typeof(ConstantIndicator <>)); // wire up the Updated events such that when we get a new piece of data from both left and right // we'll call update on this indicator. It's important to note that the CompositeIndicator only uses // the timestamp that gets passed into the Update function, his compuation is soley a function // of the left and right indicator via '_composer' IndicatorDataPoint newLeftData = null; IndicatorDataPoint newRightData = null; Left.Updated += (sender, updated) => { newLeftData = updated; // if we have left and right data (or if right is a constant) then we need to update if (newRightData != null || rightIsConstant) { Update(new T { Time = MaxTime(updated) }); // reset these to null after each update newLeftData = null; newRightData = null; } }; Right.Updated += (sender, updated) => { newRightData = updated; // if we have left and right data (or if left is a constant) then we need to update if (newLeftData != null || leftIsConstant) { Update(new T { Time = MaxTime(updated) }); // reset these to null after each update newLeftData = null; newRightData = null; } }; }
/// <summary> /// Updates the state of this indicator with the given value and returns true /// if this indicator is ready, false otherwise /// </summary> /// <param name="input">The value to use to update this indicator</param> /// <returns>True if this indicator is ready, false otherwise</returns> public bool Update(T input) { if (_previousInput != null && input.Time < _previousInput.Time) { // if we receive a time in the past, throw throw new ArgumentException(string.Format("This is a forward only indicator: {0} Input: {1} Previous: {2}", Name, input.Time.ToString("u"), _previousInput.Time.ToString("u"))); } if (!ReferenceEquals(input, _previousInput)) { // compute a new value and update our previous time Samples++; _previousInput = input; var nextResult = ValidateAndComputeNextValue(input); if (nextResult.Status == IndicatorStatus.Success) { Current = new IndicatorDataPoint(input.Time, nextResult.Value); // let others know we've produced a new data point OnUpdated(Current); } } return(IsReady); }
/// <summary> /// Computes the next value of this indicator from the given state /// </summary> /// <param name="input">The input given to the indicator</param> /// <param name="window">The window for the input history</param> /// <returns>A new value for this indicator</returns> protected override decimal ComputeNextValue(IReadOnlyWindow <IndicatorDataPoint> window, IndicatorDataPoint input) { return((decimal)Math.Sqrt((double)base.ComputeNextValue(window, input))); }
private DateTime MaxTime(IndicatorDataPoint updated) { return(new DateTime(Math.Max(updated.Time.Ticks, Math.Max(Right.Current.Time.Ticks, Left.Current.Time.Ticks)))); }
/// <summary> /// AroonUp = 100 * (period - {periods since max})/period /// </summary> /// <param name="upPeriod">The AroonUp period</param> /// <param name="max">A Maximum indicator used to compute periods since max</param> /// <param name="input">The next input data</param> /// <returns>The AroonUp value</returns> private static decimal ComputeAroonUp(int upPeriod, Maximum max, IndicatorDataPoint input) { max.Update(input); return(100m * (upPeriod - max.PeriodsSinceMaximum) / upPeriod); }
/// <summary> /// AroonDown = 100 * (period - {periods since min})/period /// </summary> /// <param name="downPeriod">The AroonDown period</param> /// <param name="min">A Minimum indicator used to compute periods since min</param> /// <param name="input">The next input data</param> /// <returns>The AroonDown value</returns> private static decimal ComputeAroonDown(int downPeriod, Minimum min, IndicatorDataPoint input) { min.Update(input); return(100m * (downPeriod - min.PeriodsSinceMinimum) / downPeriod); }
/// <summary> /// Resets this indicator to its initial state /// </summary> public virtual void Reset() { Samples = 0; _previousInput = null; Current = new IndicatorDataPoint(DateTime.MinValue, default(decimal)); }
/// <summary> /// Initializes a new instance of the Indicator class using the specified name. /// </summary> /// <param name="name">The name of this indicator</param> protected IndicatorBase(string name) { Name = name; Current = new IndicatorDataPoint(DateTime.MinValue, 0m); }