using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace QuanTAlib; /// /// A high-performance time series implementation using Structure of Arrays (SoA) layout. /// Stores Time (long) and Value (double) in separate contiguous arrays for SIMD efficiency. /// Supports "New Bar" vs "Update Last" streaming semantics. /// public class TSeries : IReadOnlyList, ITValuePublisher { protected readonly List _t; protected readonly List _v; public string Name { get; set; } = "Data"; public event Action? Pub; public TSeries() : this(0) { } public TSeries(int capacity) { _t = new List(capacity); _v = new List(capacity); } public TSeries(List time, List values) { _t = time; _v = values; } public int Count { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _v.Count; } public TValue this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => new(_t[index], _v[index]); } public TValue Last { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _v.Count > 0 ? new(_t[^1], _v[^1]) : default; } public double LastValue { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _v.Count > 0 ? _v[^1] : double.NaN; } public long LastTime { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _t.Count > 0 ? _t[^1] : 0; } /// /// Direct access to the underlying Value array as a Span for SIMD operations. /// public ReadOnlySpan Values { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => CollectionsMarshal.AsSpan(_v); } /// /// Direct access to the underlying Time array as a Span. /// public ReadOnlySpan Times { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => CollectionsMarshal.AsSpan(_t); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Add(TValue value, bool isNew) { if (isNew || _v.Count == 0) { _t.Add(value.Time); _v.Add(value.Value); } else { int lastIdx = _v.Count - 1; _t[lastIdx] = value.Time; _v[lastIdx] = value.Value; } Pub?.Invoke(value); } // Overload for backward compatibility (assumes isNew=true) [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Add(TValue value) => Add(value, true); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Add(long time, double value, bool isNew = true) => Add(new TValue(time, value), isNew); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Add(DateTime time, double value, bool isNew = true) => Add(new TValue(time, value), isNew); public void Add(IEnumerable values) { long t = DateTime.UtcNow.Ticks; foreach (var v in values) { Add(new TValue(t, v), isNew: true); t += TimeSpan.TicksPerMinute; } } // IEnumerable implementation public IEnumerator GetEnumerator() { for (int i = 0; i < _v.Count; i++) { yield return new TValue(_t[i], _v[i]); } } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); }