Files

130 lines
4.2 KiB
C#
Raw Permalink Normal View History

2024-10-27 16:11:08 -07:00
using System.Runtime.CompilerServices;
2024-09-30 06:46:07 -07:00
namespace QuanTAlib;
/// <summary>
2024-10-05 15:20:13 -07:00
/// Provides a base implementation for financial indicators that work with bar data in the QuanTAlib library.
2024-09-30 06:46:07 -07:00
/// </summary>
2024-10-05 15:20:13 -07:00
/// <remarks>
/// 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.
/// </remarks>
2024-10-08 13:59:33 -07:00
public abstract class AbstractBarBase : ITValue
2024-10-06 06:59:26 +00:00
{
2024-10-27 16:11:08 -07:00
public System.DateTime Time { get; set; }
2024-09-30 06:46:07 -07:00
public double Value { get; set; }
public bool IsNew { get; set; }
public bool IsHot { get; set; }
public TBar Input { get; set; }
2024-10-27 16:11:08 -07:00
public string Name { get; set; } = "";
2024-09-30 06:46:07 -07:00
public int WarmupPeriod { get; set; }
2024-10-27 16:11:08 -07:00
2024-10-05 15:20:13 -07:00
public TValue Tick => new(Time, Value, IsNew, IsHot);
2024-10-27 16:11:08 -07:00
2024-10-05 15:20:13 -07:00
public event ValueSignal Pub = delegate { };
2024-10-27 16:11:08 -07:00
2024-10-05 15:20:13 -07:00
protected int _index;
2024-09-30 06:46:07 -07:00
protected double _lastValidValue;
2024-10-27 16:11:08 -07:00
2024-10-06 06:59:26 +00:00
protected AbstractBarBase()
{
2024-10-05 15:20:13 -07:00
// Add parameters into constructor if needed
2024-09-30 06:46:07 -07:00
}
2024-10-05 15:20:13 -07:00
/// <summary>
/// Subscribes to bar data updates.
/// </summary>
/// <param name="source">The source of the bar data.</param>
/// <param name="args">The event arguments containing the bar data.</param>
2024-10-27 16:11:08 -07:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-09-30 06:46:07 -07:00
public void Sub(object source, in TBarEventArgs args) => Calc(args.Bar);
2024-10-05 15:20:13 -07:00
/// <summary>
/// Initializes the indicator's state.
/// </summary>
2024-10-27 16:11:08 -07:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-10-06 06:59:26 +00:00
public virtual void Init()
{
2024-09-30 06:46:07 -07:00
_index = 0;
_lastValidValue = 0;
}
2024-10-27 16:11:08 -07:00
/// <summary>
/// Checks if the input value is valid (not NaN or Infinity).
/// </summary>
/// <param name="value">The value to check.</param>
/// <returns>True if the value is valid, false otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static bool IsValidValue(double value)
{
return !double.IsNaN(value) && !double.IsInfinity(value);
}
/// <summary>
/// Creates a new TValue with the current state.
/// </summary>
/// <param name="value">The value to use.</param>
/// <returns>A new TValue instance.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected TValue CreateTValue(double value)
{
return new TValue(Time: Input.Time, Value: value, IsNew: Input.IsNew, IsHot: IsHot);
}
2024-10-05 15:20:13 -07:00
/// <summary>
/// Calculates the indicator value based on the input bar.
/// </summary>
/// <param name="input">The input bar data.</param>
/// <returns>A TValue containing the calculated result.</returns>
2024-10-06 06:59:26 +00:00
public virtual TValue Calc(TBar input)
{
2024-09-30 06:46:07 -07:00
Input = input;
2024-10-27 16:11:08 -07:00
if (!IsValidValue(input.Close))
2024-10-06 06:59:26 +00:00
{
2024-10-27 16:11:08 -07:00
return Process(CreateTValue(GetLastValid()));
2024-09-30 06:46:07 -07:00
}
2024-10-27 16:11:08 -07:00
Value = Calculation();
return Process(CreateTValue(Value));
2024-09-30 06:46:07 -07:00
}
2024-10-05 15:20:13 -07:00
/// <summary>
/// Retrieves the last valid calculated value.
/// </summary>
/// <returns>The last valid value of the indicator.</returns>
2024-10-27 16:11:08 -07:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-10-06 06:59:26 +00:00
protected virtual double GetLastValid()
{
2024-10-27 16:11:08 -07:00
return Value;
2024-09-30 06:46:07 -07:00
}
2024-10-05 15:20:13 -07:00
/// <summary>
/// Manages the state of the indicator based on whether a new bar is being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current input is a new bar.</param>
2024-09-30 06:46:07 -07:00
protected abstract void ManageState(bool isNew);
2024-10-05 15:20:13 -07:00
/// <summary>
/// Performs the actual calculation of the indicator value.
/// </summary>
/// <returns>The calculated indicator value.</returns>
2024-09-30 06:46:07 -07:00
protected abstract double Calculation();
/// <summary>
/// Processes the calculated value, updates the indicator's own state,
/// and publishes the result through an event.
/// </summary>
/// <param name="value">The calculated TValue to process.</param>
/// <returns>The processed TValue.</returns>
2024-10-27 16:11:08 -07:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-10-06 06:59:26 +00:00
protected virtual TValue Process(TValue value)
{
2024-10-27 16:11:08 -07:00
Time = value.Time;
Value = value.Value;
IsNew = value.IsNew;
IsHot = value.IsHot;
2024-09-30 06:46:07 -07:00
Pub?.Invoke(this, new ValueEventArgs(value));
return value;
}
}