namespace QuanTAlib; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Data; using System.Linq; /* TSeries is the cornerstone of all QuanTAlib classes. TSeries is a single List of tuples (time, value) and contains several operators, casts, overloads and other helpers that simplify usage of library. Think of TSeries as an equivalent of Numpy array. - includes Length property (to mimic array's method) - includes publishing and subscribing methods that attach to events */ public class TSeriesEventArgs : EventArgs { public bool update { get; set; } } public class TSeries : List<(DateTime t, double v)> { private readonly (DateTime t, double v) Default = (DateTime.MinValue, double.NaN); public IEnumerable t => this.Select(item => item.t); public IEnumerable v => this.Select(item => item.v); public (DateTime t, double v) Last => Count > 0 ? this[^1] : Default; public int Length => Count; public string Name { get; set; } public int Keep = 0; public TSeries() { this.Name = "data"; } public TSeries(string Name) { this.Name = Name; } public virtual (DateTime t, double v) Add(double v, bool update = false) { return Add((t: Count == 0 ? DateTime.Today : this[^1].t.AddDays(1), v), update); } public virtual (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { if (update) { this[^1] = TValue; } else { base.Add(TValue); } OnEvent(update); return TValue; } public virtual (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) { if (update) { this[this.Count - 1] = (TBar.t, TBar.c); } else { base.Add((TBar.t, TBar.c)); } OnEvent(update); return (TBar.t, TBar.c); } public virtual (DateTime t, double v) Add(TSeries data) { foreach (var item in data) { Add(item); } return data.Last; } public virtual (DateTime t, double v) Add(TBars data) { foreach (var item in data) { Add(item.c, false); } return (data.Last.t, data.Last.c); } public void Sub(object source, TSeriesEventArgs e) { var data = (TSeries)source; if (data == null) { return; } foreach (var item in data) { Add(item); } } public delegate void NewEventHandler(object source, TSeriesEventArgs args); public event NewEventHandler Pub; protected virtual void OnEvent(bool update = false) { if (Keep > 0) { TrimToSize(keep: Keep); } Pub?.Invoke(this, new TSeriesEventArgs { update = update }); } /// common helpers public static void BufferTrim(List buffer, double value, int period, bool update) { if (!update) { buffer.Add(value); if (buffer.Count > period && period > 0) { buffer.RemoveAt(0); } return; } buffer[^1] = value; } public virtual void Reset() { } public void TrimToSize(int keep) { if (keep >= this.Count) { return; // No need to trim if the series is already smaller than or equal to n } // Remove elements from the beginning of the list int elementsToRemove = this.Count - keep; RemoveRange(0, elementsToRemove); } }