using System.Runtime.CompilerServices; namespace QuanTAlib; /// /// APO: Absolute Price Oscillator /// A momentum indicator that measures the difference between two moving averages /// of different periods. Similar to PPO but shows absolute difference instead of percentage. /// public sealed class Apo : AbstractBase { private readonly AbstractBase _fastMa, _slowMa; /// The period for the faster moving average. /// The period for the slower moving average. /// /// Thrown when fastPeriod or slowPeriod is less than 1, or when fastPeriod is greater than or equal to slowPeriod. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Apo(int fastPeriod = 12, int slowPeriod = 26) { ArgumentOutOfRangeException.ThrowIfLessThan(fastPeriod, 1); ArgumentOutOfRangeException.ThrowIfLessThan(slowPeriod, 1); ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(fastPeriod, slowPeriod); _fastMa = new Ema(fastPeriod); _slowMa = new Ema(slowPeriod); WarmupPeriod = slowPeriod; Name = $"APO({fastPeriod},{slowPeriod})"; } /// The data source object that publishes updates. /// The period for the faster moving average. /// The period for the slower moving average. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Apo(object source, int fastPeriod, int slowPeriod) : this(fastPeriod, slowPeriod) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] protected override void ManageState(bool isNew) { if (isNew) { _index++; _lastValidValue = Input.Value; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] protected override double Calculation() { ManageState(Input.IsNew); _fastMa.Calc(Input); _slowMa.Calc(Input); return _fastMa.Value - _slowMa.Value; } }