using System; using System.Linq; using System.Runtime.CompilerServices; namespace QuanTAlib; public class Vidya : AbstractBase { private readonly int _longPeriod; private readonly double _alpha; private double _lastVIDYA, _p_lastVIDYA; private readonly CircularBuffer? _shortBuffer; private readonly CircularBuffer? _longBuffer; public Vidya(int shortPeriod, int longPeriod = 0, double alpha = 0.2) { if (shortPeriod < 1) { throw new ArgumentException("Short period must be greater than or equal to 1.", nameof(shortPeriod)); } _longPeriod = (longPeriod == 0) ? shortPeriod * 4 : longPeriod; _alpha = alpha; WarmupPeriod = _longPeriod; Name = $"Vidya({shortPeriod},{_longPeriod})"; _shortBuffer = new CircularBuffer(shortPeriod); _longBuffer = new CircularBuffer(_longPeriod); Init(); } public Vidya(object source, int shortPeriod, int longPeriod = 0, double alpha = 0.2) : this(shortPeriod, longPeriod, alpha) { var pubEvent = source.GetType().GetEvent("Pub"); pubEvent?.AddEventHandler(source, new ValueSignal(Sub)); } public override void Init() { base.Init(); _lastVIDYA = 0; } protected override void ManageState(bool isNew) { if (isNew) { _lastValidValue = Input.Value; _index++; _p_lastVIDYA = _lastVIDYA; } else { _lastVIDYA = _p_lastVIDYA; } } protected override double Calculation() { ManageState(Input.IsNew); _shortBuffer!.Add(Input.Value, Input.IsNew); _longBuffer!.Add(Input.Value, Input.IsNew); double vidya; if (_index <= _longPeriod) { vidya = _shortBuffer.Average(); } else { double shortStdDev = CalculateStdDev(_shortBuffer); double longStdDev = CalculateStdDev(_longBuffer); double s = _alpha * (shortStdDev / longStdDev); vidya = (s * Input.Value) + ((1 - s) * _lastVIDYA); } _lastVIDYA = vidya; IsHot = _index >= WarmupPeriod; return vidya; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static double CalculateStdDev(CircularBuffer buffer) { double mean = buffer.Average(); double sumSquaredDiff = buffer.Sum(x => Math.Pow(x - mean, 2)); return Math.Sqrt(sumSquaredDiff / buffer.Count); } }