From 4753a10e2925f1dc176a0d508e4bb40dbaf2e5cd Mon Sep 17 00:00:00 2001 From: Miha Kralj Date: Sun, 3 Nov 2024 16:24:08 -0800 Subject: [PATCH] codefactory corrections --- Tests/test_updates_statistics.cs | 9 --- lib/core/tbar.cs | 107 --------------------------- lib/core/tbarseries.cs | 110 ++++++++++++++++++++++++++++ lib/core/tseries.cs | 122 +++++++++++++++++++++++++++++++ lib/core/tvalue.cs | 111 ---------------------------- 5 files changed, 232 insertions(+), 227 deletions(-) create mode 100644 lib/core/tbarseries.cs create mode 100644 lib/core/tseries.cs diff --git a/Tests/test_updates_statistics.cs b/Tests/test_updates_statistics.cs index a5d901fc..e53fbd65 100644 --- a/Tests/test_updates_statistics.cs +++ b/Tests/test_updates_statistics.cs @@ -26,15 +26,6 @@ public class StatisticsUpdateTests return new TBar(DateTime.Now, open, high, low, close, 1000, IsNew); } - private TBar GetRandomBar(bool IsNew) - { - double open = GetRandomDouble(); - double high = open + Math.Abs(GetRandomDouble()); - double low = open - Math.Abs(GetRandomDouble()); - double close = low + (high - low) * GetRandomDouble(); - return new TBar(DateTime.Now, open, high, low, close, 1000, IsNew); - } - [Fact] public void Curvature_Update() { diff --git a/lib/core/tbar.cs b/lib/core/tbar.cs index c27682f4..5e949861 100644 --- a/lib/core/tbar.cs +++ b/lib/core/tbar.cs @@ -59,110 +59,3 @@ public readonly record struct TBar(DateTime Time, double Open, double High, doub [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString() => $"[{Time:yyyy-MM-dd HH:mm:ss}: O={Open:F2}, H={High:F2}, L={Low:F2}, C={Close:F2}, V={Volume:F2}]"; } - -public delegate void BarSignal(object source, in TBarEventArgs args); - -[SkipLocalsInit] -public sealed class TBarEventArgs : EventArgs -{ - public readonly TBar Bar; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TBarEventArgs(TBar bar) => Bar = bar; -} - -[SkipLocalsInit] -public class TBarSeries : List -{ - private static readonly TBar Default = new(DateTime.MinValue, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN); - - public readonly TSeries Open; - public readonly TSeries High; - public readonly TSeries Low; - public readonly TSeries Close; - public readonly TSeries Volume; - - public TBar Last => Count > 0 ? this[^1] : Default; - public TBar First => Count > 0 ? this[0] : Default; - public int Length => Count; - public string Name { get; set; } - public event BarSignal Pub = delegate { }; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TBarSeries() - { - Name = "Bar"; - Open = new TSeries(); - High = new TSeries(); - Low = new TSeries(); - Close = new TSeries(); - Volume = new TSeries(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TBarSeries(object source) : this() - { - var pubEvent = source.GetType().GetEvent("Pub"); - pubEvent?.AddEventHandler(source, new BarSignal(Sub)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public new virtual void Add(TBar bar) - { - if (bar.IsNew || base.Count == 0) - { - base.Add(bar); - } - else - { - this[^1] = bar; - } - - Pub?.Invoke(this, new TBarEventArgs(bar)); - - Open.Add(bar.Time, bar.Open, IsNew: bar.IsNew, IsHot: true); - High.Add(bar.Time, bar.High, IsNew: bar.IsNew, IsHot: true); - Low.Add(bar.Time, bar.Low, IsNew: bar.IsNew, IsHot: true); - Close.Add(bar.Time, bar.Close, IsNew: bar.IsNew, IsHot: true); - Volume.Add(bar.Time, bar.Volume, IsNew: bar.IsNew, IsHot: true); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(DateTime Time, double Open, double High, double Low, double Close, double Volume, bool IsNew = true) => - Add(new TBar(Time, Open, High, Low, Close, Volume, IsNew)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(double Open, double High, double Low, double Close, double Volume, bool IsNew = true) => - Add(new TBar(DateTime.Now, Open, High, Low, Close, Volume, IsNew)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(TBarSeries series) - { - if (series == this) - { - // If adding itself, create a copy to avoid modification during enumeration - var copy = new TBarSeries { Name = Name }; - copy.AddRange(this); - AddRange(copy); - } - else - { - AddRange(series); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public new virtual void AddRange(IEnumerable collection) - { - foreach (var item in collection) - { - Add(item); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Sub(object source, in TBarEventArgs args) - { - Add(args.Bar); - } -} diff --git a/lib/core/tbarseries.cs b/lib/core/tbarseries.cs new file mode 100644 index 00000000..32163238 --- /dev/null +++ b/lib/core/tbarseries.cs @@ -0,0 +1,110 @@ +using System.Runtime.CompilerServices; + +namespace QuanTAlib; + +public delegate void BarSignal(object source, in TBarEventArgs args); + +[SkipLocalsInit] +public sealed class TBarEventArgs : EventArgs +{ + public readonly TBar Bar; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TBarEventArgs(TBar bar) => Bar = bar; +} + +[SkipLocalsInit] +public class TBarSeries : List +{ + private static readonly TBar Default = new(DateTime.MinValue, double.NaN, double.NaN, double.NaN, double.NaN, double.NaN); + + public TSeries Open { get; init; } + public TSeries High { get; init; } + public TSeries Low { get; init; } + public TSeries Close { get; init; } + public TSeries Volume { get; init; } + + public TBar Last => Count > 0 ? this[^1] : Default; + public TBar First => Count > 0 ? this[0] : Default; + public int Length => Count; + public string Name { get; set; } + public event BarSignal Pub = delegate { }; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TBarSeries() + { + Name = "Bar"; + Open = new TSeries(); + High = new TSeries(); + Low = new TSeries(); + Close = new TSeries(); + Volume = new TSeries(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TBarSeries(object source) : this() + { + var pubEvent = source.GetType().GetEvent("Pub"); + pubEvent?.AddEventHandler(source, new BarSignal(Sub)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public new virtual void Add(TBar bar) + { + if (bar.IsNew || base.Count == 0) + { + base.Add(bar); + } + else + { + this[^1] = bar; + } + + Pub?.Invoke(this, new TBarEventArgs(bar)); + + Open.Add(bar.Time, bar.Open, IsNew: bar.IsNew, IsHot: true); + High.Add(bar.Time, bar.High, IsNew: bar.IsNew, IsHot: true); + Low.Add(bar.Time, bar.Low, IsNew: bar.IsNew, IsHot: true); + Close.Add(bar.Time, bar.Close, IsNew: bar.IsNew, IsHot: true); + Volume.Add(bar.Time, bar.Volume, IsNew: bar.IsNew, IsHot: true); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(DateTime Time, double Open, double High, double Low, double Close, double Volume, bool IsNew = true) => + Add(new TBar(Time, Open, High, Low, Close, Volume, IsNew)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(double Open, double High, double Low, double Close, double Volume, bool IsNew = true) => + Add(new TBar(DateTime.Now, Open, High, Low, Close, Volume, IsNew)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(TBarSeries series) + { + if (series == this) + { + // If adding itself, create a copy to avoid modification during enumeration + var copy = new TBarSeries { Name = Name }; + copy.AddRange(this); + AddRange(copy); + } + else + { + AddRange(series); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public new virtual void AddRange(IEnumerable collection) + { + foreach (var item in collection) + { + Add(item); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Sub(object source, in TBarEventArgs args) + { + Add(args.Bar); + } +} diff --git a/lib/core/tseries.cs b/lib/core/tseries.cs new file mode 100644 index 00000000..acbe3ac6 --- /dev/null +++ b/lib/core/tseries.cs @@ -0,0 +1,122 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; + +namespace QuanTAlib; + +public delegate void ValueSignal(object source, in ValueEventArgs args); + +[SkipLocalsInit] +public sealed class ValueEventArgs : EventArgs +{ + public readonly TValue Tick; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ValueEventArgs(TValue value) => Tick = value; +} + +[SkipLocalsInit] +public class TSeries : List +{ + private static readonly TValue Default = new(DateTime.MinValue, double.NaN); + + public IEnumerable t => this.Select(item => item.t); + public IEnumerable v => this.Select(item => item.v); + public TValue Last => Count > 0 ? this[^1] : Default; + public TValue First => Count > 0 ? this[0] : Default; + public int Length => Count; + public string Name { get; set; } + + /// + /// Event that publishes value updates to subscribers. This event is used in the pub/sub pattern + /// where TSeries instances can subscribe to updates from other data sources through the Sub method, + /// and publish their own updates to downstream subscribers. + /// + [SuppressMessage("Minor Code Smell", "S3264:Events should be invoked", Justification = "Event is invoked through delegate")] + public event ValueSignal Pub = delegate { }; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TSeries() + { + Name = "Data"; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TSeries(object source) : this() + { + var pubEvent = source.GetType().GetEvent("Pub"); + if (pubEvent != null) + { + pubEvent.AddEventHandler(source, new ValueSignal(Sub)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator List(TSeries series) => series.Select(item => item.Value).ToList(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator double[](TSeries series) => series.Select(item => item.Value).ToArray(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public new virtual void Add(TValue tick) + { + if (tick.IsNew || base.Count == 0) + { + base.Add(tick); + } + else + { + this[^1] = tick; + } + Pub?.Invoke(this, new ValueEventArgs(tick)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Add(DateTime Time, double Value, bool IsNew = true, bool IsHot = true) => + Add(new TValue(Time, Value, IsNew, IsHot)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Add(double Value, bool IsNew = true, bool IsHot = true) => + Add(new TValue(DateTime.UtcNow, Value, IsNew, IsHot)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(IEnumerable values) + { + var valueList = values.ToList(); + int count = valueList.Count; + DateTime startTime = DateTime.UtcNow - TimeSpan.FromHours(count); + + for (int i = 0; i < count; i++) + { + Add(startTime, valueList[i]); + startTime = startTime.AddHours(1); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(TSeries series) + { + if (series == this) + { + // If adding itself, create a copy to avoid modification during enumeration + var copy = new TSeries { Name = Name }; + copy.AddRange(this); + AddRange(copy); + } + else + { + AddRange(series); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public new virtual void AddRange(IEnumerable collection) + { + foreach (var item in collection) + { + Add(item); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Sub(object source, in ValueEventArgs args) => Add(args.Tick); +} diff --git a/lib/core/tvalue.cs b/lib/core/tvalue.cs index 8e54ba48..04f4e517 100644 --- a/lib/core/tvalue.cs +++ b/lib/core/tvalue.cs @@ -39,114 +39,3 @@ public readonly record struct TValue(DateTime Time, double Value, bool IsNew = t [MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString() => $"[{Time:yyyy-MM-dd HH:mm:ss}, {Value:F2}, IsNew: {IsNew}, IsHot: {IsHot}]"; } - -public delegate void ValueSignal(object source, in ValueEventArgs args); - -[SkipLocalsInit] -public sealed class ValueEventArgs : EventArgs -{ - public readonly TValue Tick; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ValueEventArgs(TValue value) => Tick = value; -} - -[SkipLocalsInit] -public class TSeries : List -{ - private static readonly TValue Default = new(DateTime.MinValue, double.NaN); - - public IEnumerable t => this.Select(item => item.t); - public IEnumerable v => this.Select(item => item.v); - public TValue Last => Count > 0 ? this[^1] : Default; - public TValue First => Count > 0 ? this[0] : Default; - public int Length => Count; - public string Name { get; set; } - public event ValueSignal Pub = delegate { }; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TSeries() - { - Name = "Data"; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public TSeries(object source) : this() - { - var pubEvent = source.GetType().GetEvent("Pub"); - if (pubEvent != null) - { - pubEvent.AddEventHandler(source, new ValueSignal(Sub)); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator List(TSeries series) => series.Select(item => item.Value).ToList(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator double[](TSeries series) => series.Select(item => item.Value).ToArray(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public new virtual void Add(TValue tick) - { - if (tick.IsNew || base.Count == 0) - { - base.Add(tick); - } - else - { - this[^1] = tick; - } - Pub?.Invoke(this, new ValueEventArgs(tick)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public virtual void Add(DateTime Time, double Value, bool IsNew = true, bool IsHot = true) => - Add(new TValue(Time, Value, IsNew, IsHot)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public virtual void Add(double Value, bool IsNew = true, bool IsHot = true) => - Add(new TValue(DateTime.UtcNow, Value, IsNew, IsHot)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(IEnumerable values) - { - var valueList = values.ToList(); - int count = valueList.Count; - DateTime startTime = DateTime.UtcNow - TimeSpan.FromHours(count); - - for (int i = 0; i < count; i++) - { - Add(startTime, valueList[i]); - startTime = startTime.AddHours(1); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Add(TSeries series) - { - if (series == this) - { - // If adding itself, create a copy to avoid modification during enumeration - var copy = new TSeries { Name = Name }; - copy.AddRange(this); - AddRange(copy); - } - else - { - AddRange(series); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public new virtual void AddRange(IEnumerable collection) - { - foreach (var item in collection) - { - Add(item); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Sub(object source, in ValueEventArgs args) => Add(args.Tick); -}