using System.Runtime.CompilerServices; namespace QuanTAlib; /// /// Provides a base implementation for financial indicators that work with bar data in the QuanTAlib library. /// /// /// This abstract class implements the iTValue interface and defines common properties /// and methods used by inheriting indicator types. It handles the basic flow of /// receiving bar data, performing calculations, and publishing results. /// public abstract class AbstractBarBase : ITValue { public System.DateTime Time { get; set; } public double Value { get; set; } public bool IsNew { get; set; } public bool IsHot { get; set; } public TBar Input { get; set; } public string Name { get; set; } = ""; public int WarmupPeriod { get; set; } public TValue Tick => new(Time, Value, IsNew, IsHot); public event ValueSignal Pub = delegate { }; protected int _index; protected double _lastValidValue; protected AbstractBarBase() { // Add parameters into constructor if needed } /// /// Subscribes to bar data updates. /// /// The source of the bar data. /// The event arguments containing the bar data. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Sub(object source, in TBarEventArgs args) => Calc(args.Bar); /// /// Initializes the indicator's state. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Init() { _index = 0; _lastValidValue = 0; } /// /// Checks if the input value is valid (not NaN or Infinity). /// /// The value to check. /// True if the value is valid, false otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] protected static bool IsValidValue(double value) { return !double.IsNaN(value) && !double.IsInfinity(value); } /// /// Creates a new TValue with the current state. /// /// The value to use. /// A new TValue instance. [MethodImpl(MethodImplOptions.AggressiveInlining)] protected TValue CreateTValue(double value) { return new TValue(Time: Input.Time, Value: value, IsNew: Input.IsNew, IsHot: IsHot); } /// /// Calculates the indicator value based on the input bar. /// /// The input bar data. /// A TValue containing the calculated result. public virtual TValue Calc(TBar input) { Input = input; if (!IsValidValue(input.Close)) { return Process(CreateTValue(GetLastValid())); } Value = Calculation(); return Process(CreateTValue(Value)); } /// /// Retrieves the last valid calculated value. /// /// The last valid value of the indicator. [MethodImpl(MethodImplOptions.AggressiveInlining)] protected virtual double GetLastValid() { return Value; } /// /// Manages the state of the indicator based on whether a new bar is being processed. /// /// Indicates whether the current input is a new bar. protected abstract void ManageState(bool isNew); /// /// Performs the actual calculation of the indicator value. /// /// The calculated indicator value. protected abstract double Calculation(); /// /// Processes the calculated value, updates the indicator's own state, /// and publishes the result through an event. /// /// The calculated TValue to process. /// The processed TValue. [MethodImpl(MethodImplOptions.AggressiveInlining)] protected virtual TValue Process(TValue value) { Time = value.Time; Value = value.Value; IsNew = value.IsNew; IsHot = value.IsHot; Pub?.Invoke(this, new ValueEventArgs(value)); return value; } }