namespace QuanTAlib; using System; /* TBars class - includes all series for common data used in indicators and other calculations. Has a bit limited overloading and casting (compared to TSeries) Includes Select(int) method to simplify choosing the most optimal data source for indicators Includes the most basic pricing calcs: HL2, OC2, OHL3, HLC3, OHLC4, HLCC4 (it is 'cheaper' to calculate them once during data capture than each time during data analysis) */ public class TBars : System.Collections.Generic.List<(DateTime t, double o, double h, double l, double c, double v)> { public string Name { get; set; } private readonly TSeries _open = new("open"); private readonly TSeries _high = new("high"); private readonly TSeries _low = new("low"); private readonly TSeries _close = new("close"); private readonly TSeries _volume = new("volume"); private readonly TSeries _hl2 = new("HL2"); private readonly TSeries _oc2 = new("OC2"); private readonly TSeries _ohl3 = new("OHL3"); private readonly TSeries _hlc3 = new("HLC3"); private readonly TSeries _ohlc4 = new("OHLC4"); private readonly TSeries _hlcc4 = new("HLCC4"); public TSeries Open => this._open; public TSeries High => this._high; public TSeries Low => this._low; public TSeries Close => this._close; public TSeries Volume => this._volume; public TSeries HL2 => this._hl2; public TSeries OC2 => this._oc2; public TSeries OHL3 => this._ohl3; public TSeries HLC3 => this._hlc3; public TSeries OHLC4 => this._ohlc4; public TSeries HLCC4 => this._hlcc4; public TBars() { } public TBars(string Name) { this.Name = Name; } public (DateTime t, double o, double h, double l, double c, double v) Last => this[^1]; public TBars Tail(int count = 10) { TBars outBars = new(); if (count > this.Count) { count = this.Count; } for (int i = this.Count - count; i < this.Count; i++) { outBars.Add(this[i]); } return outBars; } public TSeries Select(int source) { return source switch { 0 => _open, 1 => _high, 2 => _low, 3 => _close, 4 => _hl2, 5 => _oc2, 6 => _ohl3, 7 => _hlc3, 8 => _ohlc4, _ => _hlcc4, }; } public static string SelectStr(int source) { return source switch { 0 => "Open", 1 => "High", 2 => "Low", 3 => "Close", 4 => "HL2", 5 => "OC2", 6 => "OHL3", 7 => "HLC3", 8 => "OHLC4", _ => "HLCC4", }; } public virtual (DateTime t, double v) Add((double o, double h, double l, double c, double v) p, bool update = false) => Add((t: (this.Count == 0) ? DateTime.Today : this[^1].t.AddDays(1),p.o,p.h,p.l,p.c,p.v),update); public virtual (DateTime t, double v) Add(double o, double h, double l, double c, double v, bool update = false) => Add((o,h,l,c,v),update); public virtual (DateTime t, double v) Add(DateTime t, double o, double h, double l, double c, double v, bool update = false) => this.Add((t, o, h, l, c, v), update); 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[^1] = TBar; } else { base.Add(TBar); } _open.Add((TBar.t, TBar.o), update); _high.Add((TBar.t, TBar.h), update); _low.Add((TBar.t, TBar.l), update); _close.Add((TBar.t, TBar.c), update); _volume.Add((TBar.t, TBar.v), update); _hl2.Add((TBar.t, (TBar.h + TBar.l) * 0.5), update); _oc2.Add((TBar.t, (TBar.o + TBar.c) * 0.5), update); _ohl3.Add((TBar.t, (TBar.o + TBar.h + TBar.l) * 0.333333333333333), update); _hlc3.Add((TBar.t, (TBar.h + TBar.l + TBar.c) * 0.333333333333333), update); _ohlc4.Add((TBar.t, (TBar.o + TBar.h + TBar.l + TBar.c) * 0.25), update); _hlcc4.Add((TBar.t, (TBar.h + TBar.l + TBar.c + TBar.c) * 0.25), update); this.OnEvent(update); return (TBar.t, (TBar.o + TBar.h + TBar.l + TBar.c) * 0.25); } public delegate void NewDataEventHandler(object source, TSeriesEventArgs args); public event NewDataEventHandler Pub; protected virtual void OnEvent(bool update = false) { if (Pub != null && Pub.Target != this) { Pub(this, new TSeriesEventArgs { update = update }); } } public void Sub(object source, TSeriesEventArgs e) { TBars ss = (TBars)source; if (ss.Count > 1) { for (int i = 0; i < ss.Count; i++) { this.Add(ss[i]); } } else { this.Add(ss[^1], e.update); } } /// common helpers public static void BufferTrim(System.Collections.Generic.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() { } }