diff --git a/.github/workflows/main_automation.yml b/.github/workflows/main_automation.yml index cf67c903..f6307300 100644 --- a/.github/workflows/main_automation.yml +++ b/.github/workflows/main_automation.yml @@ -87,6 +87,20 @@ jobs: title: "Latest Build" files: /Quantower/Settings/Scripts/Indicators/QuanTAlib/*.dll + - name: Authenticate to Github packages source + run: dotnet nuget add source + --username mihakralj + --password ${{ secrets.GITHUB_TOKEN }} + --store-password-in-clear-text + --name github "https://nuget.pkg.github.com/mihakralj/index.json" + + - name: Push package to github + if: ${{ github.ref == 'refs/heads/dev' }} + run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg' + --source https://nuget.pkg.github.com/mihakralj/index.json + --skip-duplicate + --no-symbols + - name: Push package to nuget.org if: ${{ github.ref == 'refs/heads/main' }} run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg' diff --git a/Quantower/Indicators/ATR_chart.cs b/Quantower/Indicators/ATR_chart.cs index ae9795a3..d13e91b9 100644 --- a/Quantower/Indicators/ATR_chart.cs +++ b/Quantower/Indicators/ATR_chart.cs @@ -30,8 +30,8 @@ public class ATR_chart : Indicator this.ShortName = "ATR (" + this.Period + ")"; this.bars = new(); this.indicator = new(source: bars, period: this.Period, useNaN: false); - } - + } + protected override void OnUpdate(UpdateArgs args) { bool update = !(args.Reason == UpdateReason.NewBar || diff --git a/Quantower/Indicators/WMAPE_chart.cs b/Quantower/Indicators/WMAPE_chart.cs index f75dbecd..54fb4256 100644 --- a/Quantower/Indicators/WMAPE_chart.cs +++ b/Quantower/Indicators/WMAPE_chart.cs @@ -51,11 +51,6 @@ public class WMAPE_chart : Indicator this.bars.Add(this.Time(), this.GetPrice(PriceType.Open), this.GetPrice(PriceType.High), this.GetPrice(PriceType.Low), this.GetPrice(PriceType.Close), this.GetPrice(PriceType.Volume), update); double result = this.indicator[this.indicator.Count - 1].v; - this.SetValue(result, 0); - - - - } } diff --git a/Quantower/Indicators/ZLMA_chart.cs b/Quantower/Indicators/ZLMA_chart.cs deleted file mode 100644 index 35cddbdf..00000000 --- a/Quantower/Indicators/ZLMA_chart.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System.Collections; -using System.Drawing; -using System.Drawing.Text; -using TradingPlatform.BusinessLayer; -namespace QuanTAlib; - -public class ZLMA_chart : Indicator -{ - #region Parameters - - [InputParameter("Smoothing period", 0, 1, 999, 1, 1)] - private readonly int Period = 10; - - [InputParameter("Data source", 1, variants: new object[] - { "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5, - "OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })] - private readonly int DataSource = 3; - - [InputParameter("MA algorithm", 2, variants: new object[] - { "SMA", 0, - "WMA", 1, - "EMA", 2, - "DEMA", 3, - "TEMA", 4, - "HMA", 5, - "KAMA", 6, - "JMA", 7, - "SMMA", 8 - })] - private readonly int matype = 2; - -#endregion Parameters - - private TBars bars; - /////// - private TSeries indicator; - /////// - - public ZLMA_chart() - { - this.SeparateWindow = false; - this.Name = "ZLMA - Zero-lag Moving Average"; - this.Description = "Zero-Lag Moving Average description"; - this.AddLineSeries("ZLMA", Color.RoyalBlue, 3, LineStyle.Solid); - } - - protected override void OnInit() - { - this.bars = new(); - string maname = matype switch - { - 0 => "SMA", - 1 => "WMA", - 2 => "EMA", - 3 => "DEMA", - 4 => "TEMA", - 5 => "HMA", - 6 => "KAMA", - 7 => "JMA", - 8 => "SMMA", - _ => "???" - }; - - this.ShortName = "ZLMA (" + maname + ", " + TBars.SelectStr(this.DataSource) + ", " + this.Period + ")"; - ZL_Series zerolag = new(source: bars.Select(this.DataSource), period: this.Period, useNaN: false); - this.indicator = matype switch - { - 0 => new SMA_Series(source: zerolag, period: this.Period, useNaN: false), - 1 => new WMA_Series(source: zerolag, period: this.Period, useNaN: false), - 2 => new EMA_Series(source: zerolag, period: this.Period, useNaN: false), - 3 => new DEMA_Series(source: zerolag, period: this.Period, useNaN: false), - 4 => new TEMA_Series(source: zerolag, period: this.Period, useNaN: false), - 5 => new HMA_Series(source: zerolag, period: this.Period, useNaN: false), - 6 => new KAMA_Series(source: zerolag, period: this.Period, useNaN: false), - 7 => new JMA_Series(source: zerolag, period: this.Period, useNaN: false), - 8 => new SMMA_Series(source: zerolag, period: this.Period, useNaN: false), - _ => new EMA_Series(source: zerolag, period: this.Period, useNaN: false) - }; - } - - protected override void OnUpdate(UpdateArgs args) - { - bool update = !(args.Reason == UpdateReason.NewBar || - args.Reason == UpdateReason.HistoricalBar); - this.bars.Add(this.Time(), this.GetPrice(PriceType.Open), - this.GetPrice(PriceType.High), this.GetPrice(PriceType.Low), - this.GetPrice(PriceType.Close), - this.GetPrice(PriceType.Volume), update); - - double result = this.indicator[this.indicator.Count-1].v; - this.SetValue(result); - } -} diff --git a/Source/Basics/Abstracts.cs b/Source/Basics/Abstracts.cs index d20be702..434f3e7a 100644 --- a/Source/Basics/Abstracts.cs +++ b/Source/Basics/Abstracts.cs @@ -32,23 +32,14 @@ public abstract class Single_TSeries_Indicator : TSeries public new virtual void Add((System.DateTime t, double v) TValue, bool update) => base.Add(TValue, update); // potentially overridable Add() method for the whole series (could be replaced with faster bulk algo) - public virtual void Add(TSeries data) - { - for (int i = 0; i < data.Count; i++) { this.Add(TValue: data[i], update: false); } - } + public virtual void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { this.Add(TValue: data[i], update: false); }} - public new void Add((System.DateTime t, double v) TValue) - => this.Add(TValue: TValue, update: false); - public void Add(bool update) - => this.Add(TValue: this._data[this._data.Count - 1], update: update); - public void Add() - => this.Add(TValue: this._data[this._data.Count - 1], update: false); - public new void Sub(object source, TSeriesEventArgs e) - => this.Add(TValue: this._data[this._data.Count - 1], update: e.update); + public new void Add((System.DateTime t, double v) TValue) => this.Add(TValue: TValue, update: false); + public void Add(bool update) => this.Add(TValue: this._data[this._data.Count - 1], update: update); + public void Add() => this.Add(TValue: this._data[this._data.Count - 1], update: false); + public new void Sub(object source, TSeriesEventArgs e) => this.Add(TValue: this._data[this._data.Count - 1], update: e.update); } - - public abstract class Pair_TSeries_Indicator : TSeries { protected readonly TSeries _d1; @@ -83,24 +74,14 @@ public abstract class Pair_TSeries_Indicator : TSeries } // overridable Add(Tvalue, Tvalue) method to add/update a single value at the end of the list - public virtual void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update) - => base.Add(TValue: (TValue1.t, 0), update: update); // default inserts zeros - + public virtual void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update) => base.Add(TValue: (TValue1.t, 0), update: update); // default inserts zeros // potentially overridable Add() bulk variations (could be replaced with faster bulk algos) - public virtual void Add(TSeries d1, TSeries d2) { - for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], d2[i], update: false); } - } - public virtual void Add(TSeries d1, double dd2) { - for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], (d1[i].t, dd2), update: false); } - } - public virtual void Add(double dd1, TSeries d2) { - for (int i = 0; i < d2.Count; i++) { this.Add((d2[i].t, dd1), d2[i], update: false); } - } + public virtual void Add(TSeries d1, TSeries d2) { for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], d2[i], update: false); }} + public virtual void Add(TSeries d1, double dd2) { for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], (d1[i].t, dd2), update: false); }} + public virtual void Add(double dd1, TSeries d2) { for (int i = 0; i < d2.Count; i++) { this.Add((d2[i].t, dd1), d2[i], update: false); }} - - public void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2) - => this.Add(TValue1, TValue2, update: false); + public void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2) => this.Add(TValue1, TValue2, update: false); public void Add(bool update) { @@ -123,12 +104,9 @@ public abstract class Pair_TSeries_Indicator : TSeries } public void Add() => this.Add(update: false); - - public new void Sub(object source, TSeriesEventArgs e) - => this.Add(e.update); + public new void Sub(object source, TSeriesEventArgs e) => this.Add(e.update); } - public abstract class Single_TBars_Indicator : TSeries { protected readonly int _p; @@ -148,22 +126,10 @@ public abstract class Single_TBars_Indicator : TSeries public virtual void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar, bool update) => base.Add((TBar.t, 0.0), update); // potentially overridable Add() method for the whole bars or series (could be replaced with faster bulk algo) - public virtual void Add(TBars bars) - { - for (int i = 0; i < bars.Count; i++) { this.Add(TBar: bars[i], update: false); } - } - - public virtual void Add(TSeries data) - { - for (int i = 0; i < data.Count; i++) { base.Add(TValue: data[i], update: false); } - } - -public void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar) - => this.Add(TBar: TBar, update: false); - public void Add(bool update) - => this.Add(TBar: this._bars[this._bars.Count - 1], update: update); - public void Add() - => this.Add(TBar: this._bars[this._bars.Count - 1], update: false); - public new void Sub(object source, TSeriesEventArgs e) - => this.Add(TBar: this._bars[this._bars.Count - 1], update: e.update); + public virtual void Add(TBars bars) { for (int i = 0; i < bars.Count; i++) { this.Add(TBar: bars[i], update: false); }} + public virtual void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { base.Add(TValue: data[i], update: false); }} + public void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar) => this.Add(TBar: TBar, update: false); + public void Add(bool update) => this.Add(TBar: this._bars[this._bars.Count - 1], update: update); + public void Add() => this.Add(TBar: this._bars[this._bars.Count - 1], update: false); + public new void Sub(object source, TSeriesEventArgs e) => this.Add(TBar: this._bars[this._bars.Count - 1], update: e.update); } diff --git a/Source/Basics/MAX_Series.cs b/Source/Basics/MAX_Series.cs index b22ce2aa..591f6739 100644 --- a/Source/Basics/MAX_Series.cs +++ b/Source/Basics/MAX_Series.cs @@ -22,7 +22,10 @@ public class MAX_Series : Single_TSeries_Indicator double _max = TValue.v; for (int i = 0; i < this._buffer.Count; i++) - { _max = (this._buffer[i] > _max) ? this._buffer[i] : _max; } + { + //_max = (this._buffer[i] > _max) ? this._buffer[i] : _max; + _max = Math.Max(this._buffer[i], _max); + } var result = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _max); diff --git a/Source/Basics/MIN_Series.cs b/Source/Basics/MIN_Series.cs index 8c513d8e..4209d0b1 100644 --- a/Source/Basics/MIN_Series.cs +++ b/Source/Basics/MIN_Series.cs @@ -22,7 +22,10 @@ public class MIN_Series : Single_TSeries_Indicator double _min = TValue.v; for (int i = 0; i < this._buffer.Count; i++) - { _min = (this._buffer[i] < _min) ? this._buffer[i] : _min; } + { + //_min = (this._buffer[i] < _min) ? this._buffer[i] : _min; + _min = Math.Min(this._buffer[i], _min); + } var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _min); diff --git a/Source/Basics/TBars.cs b/Source/Basics/TBars.cs index 849ca182..31954ef4 100644 --- a/Source/Basics/TBars.cs +++ b/Source/Basics/TBars.cs @@ -75,7 +75,6 @@ public class TBars : System.Collections.Generic.List<(DateTime t, double o, doub }; } - public void Add((DateTime t, double o, double h, double l, double c, double v) i, bool update = false) => Add(i.t, i.o, i.h, i.l, i.c, i.v, update); @@ -130,6 +129,4 @@ public class TBars : System.Collections.Generic.List<(DateTime t, double o, doub Pub(this, new TSeriesEventArgs { update = update }); } } - - } diff --git a/Source/Basics/ZL_Series.cs b/Source/Basics/ZL_Series.cs index 04fc419d..7e06bf96 100644 --- a/Source/Basics/ZL_Series.cs +++ b/Source/Basics/ZL_Series.cs @@ -30,6 +30,5 @@ public class ZL_Series : Single_TSeries_Indicator var ret = (TValue.t, (base.Count==0 && base._NaN) ? double.NaN : _zl ); base.Add(ret, update); - } } \ No newline at end of file diff --git a/Source/Feeds/Alphavantage_Feed.cs b/Source/Feeds/Alphavantage_Feed.cs index 721d2f2d..ab485dfb 100644 --- a/Source/Feeds/Alphavantage_Feed.cs +++ b/Source/Feeds/Alphavantage_Feed.cs @@ -55,4 +55,3 @@ public class Alphavantage_Feed : TBars return (date, o, h, l, c, v); } } - diff --git a/Source/Feeds/GBM_Feed.cs b/Source/Feeds/GBM_Feed.cs index dbc9559e..0adcde1d 100644 --- a/Source/Feeds/GBM_Feed.cs +++ b/Source/Feeds/GBM_Feed.cs @@ -38,11 +38,11 @@ public class GBM_Feed : TBars double OCMax = Math.Max(Open,Close); double High = (GBM_value(seed, volatility*0.5, 0)); - High = (HighOCMin)? 2*OCMin-Low : Low; + Low = (Low>OCMin)? (2 * OCMin) - Low : Low; double Volume = GBM_value(seed*10, volatility*2, Drift:0); @@ -55,6 +55,6 @@ public class GBM_Feed : TBars double U1 = 1.0-rnd.NextDouble(); double U2 = 1.0-rnd.NextDouble(); double Z = Math.Sqrt(-2.0 * Math.Log(U1)) * Math.Sin(2.0 * Math.PI * U2); - return Seed * Math.Exp( Drift - (Volatility*Volatility*0.5) + Volatility * Z); + return Seed * Math.Exp( Drift - (Volatility*Volatility*0.5) + (Volatility * Z)); } } \ No newline at end of file diff --git a/Source/Feeds/RND_Feed.cs b/Source/Feeds/RND_Feed.cs index b7c42e27..3105d79f 100644 --- a/Source/Feeds/RND_Feed.cs +++ b/Source/Feeds/RND_Feed.cs @@ -17,10 +17,10 @@ public class RND_Feed : TBars double c = startvalue; for (int i = 0; i < bars; i++) { - double o = Math.Round(c + c * (volatility * 0.1 * rnd.NextDouble() - 0.005), 2); - double h = Math.Round(o + c * volatility * rnd.NextDouble(), 2); - double l = Math.Round(o - c * volatility * rnd.NextDouble(), 2); - c = Math.Round(l + (h - l) * rnd.NextDouble(), 2); + double o = Math.Round(c + (c * (((volatility * 0.1) * rnd.NextDouble()) - 0.005)), 2); + double h = Math.Round(o + (c * volatility * rnd.NextDouble()), 2); + double l = Math.Round(o - (c * volatility * rnd.NextDouble()), 2); + c = Math.Round(l + ((h - l) * rnd.NextDouble()), 2); double v = Math.Round(1000 * rnd.NextDouble(), 2); this.Add(DateTime.Today.AddDays(i - bars), o, h, l, c, v); } diff --git a/Source/Indicators/CCI_Series.cs b/Source/Momentum/CCI_Series.cs similarity index 94% rename from Source/Indicators/CCI_Series.cs rename to Source/Momentum/CCI_Series.cs index bac14b9e..f1f6c737 100644 --- a/Source/Indicators/CCI_Series.cs +++ b/Source/Momentum/CCI_Series.cs @@ -20,14 +20,13 @@ public class CCI_Series : Single_TBars_Indicator { private readonly System.Collections.Generic.List _tp = new(); - public CCI_Series(TBars source, int period = 10, bool useNaN = false) - : base(source, period: period, useNaN: useNaN) { - + public CCI_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) + { if (_bars.Count > 0) { base.Add(_bars); } } - public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) { - + public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) + { double _tpItem = (TBar.h + TBar.l + TBar.c) / 3.0; if (update) { this._tp[this._tp.Count - 1] = _tpItem; } else { this._tp.Add(_tpItem); } if (this._tp.Count > this._p) { this._tp.RemoveAt(0); } diff --git a/Source/QuanTAlib.csproj b/Source/QuanTAlib.csproj index 443980bc..c43aedcb 100644 --- a/Source/QuanTAlib.csproj +++ b/Source/QuanTAlib.csproj @@ -1,7 +1,7 @@  - 0.1.17 + 0.1.18 QuanTAlib diff --git a/Source/Statistics/KURT_Series.cs b/Source/Statistics/KURT_Series.cs index be84dabe..ed0a45c4 100644 --- a/Source/Statistics/KURT_Series.cs +++ b/Source/Statistics/KURT_Series.cs @@ -54,7 +54,7 @@ public class KURT_Series : Single_TSeries_Indicator } double _Vx = _s2 / (_n - 1); - double _kurt = (_n > 3) ? (((_n * (_n + 1)) / ((_n - 1) * (_n - 2) * (_n - 3))) * (_s4 / (_Vx * _Vx)) - (3 * ((_n - 1) * (_n - 1) / ((_n - 2) * (_n - 3))))) : Double.NaN; + double _kurt = (_n > 3) ? ((((_n * (_n + 1)) / (((_n - 1) * (_n - 2)) * (_n - 3))) * (_s4 / (_Vx * _Vx))) - (3 * (((_n - 1) * (_n - 1)) / ((_n - 2) * (_n - 3))))) : Double.NaN; var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? Double.NaN : _kurt); base.Add(result, update); diff --git a/Source/Statistics/MED_Series.cs b/Source/Statistics/MED_Series.cs index 8d0758ee..8ea91d58 100644 --- a/Source/Statistics/MED_Series.cs +++ b/Source/Statistics/MED_Series.cs @@ -37,7 +37,7 @@ public class MED_Series : Single_TSeries_Indicator System.Collections.Generic.List _s = new(this._buffer); _s.Sort(); int _p1 = _s.Count / 2; - int _p2 = Math.Max(0, _s.Count / 2 - 1); + int _p2 = Math.Max(0, (_s.Count / 2) - 1); double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2; var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _med); diff --git a/Source/Indicators/ALMA_Series.cs b/Source/Trends/ALMA_Series.cs similarity index 96% rename from Source/Indicators/ALMA_Series.cs rename to Source/Trends/ALMA_Series.cs index f91267e6..ab3f4593 100644 --- a/Source/Indicators/ALMA_Series.cs +++ b/Source/Trends/ALMA_Series.cs @@ -1,68 +1,65 @@ -namespace QuanTAlib; -using System; - -/* -ALMA: Arnaud Legoux Moving Average - The ALMA moving average uses the curve of the Normal (Gauss) distribution, which - can be shifted from 0 to 1. This allows regulating the smoothness and high - sensitivity of the indicator. Sigma is another parameter that is responsible for - the shape of the curve coefficients. This moving average reduces lag of the data - in conjunction with smoothing to reduce noise. - - -Sources: - https://phemex.com/academy/what-is-arnaud-legoux-moving-averages - https://www.prorealcode.com/prorealtime-indicators/alma-arnaud-legoux-moving-average/ - - */ - -public class ALMA_Series : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer = new(); - private readonly double[] _weight; - private double _norm; - private readonly double _offset, _sigma; - - public ALMA_Series(TSeries source, int period, double offset = 0.85, double sigma = 6.0, bool useNaN = false) - : base(source, period, useNaN) - { - _offset = offset; - _sigma = sigma; - _weight = new double[period]; - - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } - else { this._buffer.Add(TValue.v); } - if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); } - - if (this._buffer.Count <= _p) { calc_weights(); } - - double _weightedSum = 0; - for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; } - double _alma = _weightedSum / _norm; - - var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _alma); - base.Add(ret, update); - } - - private void calc_weights() - { - int _len = this._buffer.Count; - _norm = 0; - double _m = _offset * (_len - 1); - double _s = _len / _sigma; - for (int i = 0; i < _len; i++) - { - double _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s)); - _weight[i] = _wt; - _norm += _wt; - } - } - -} - - +namespace QuanTAlib; +using System; + +/* +ALMA: Arnaud Legoux Moving Average + The ALMA moving average uses the curve of the Normal (Gauss) distribution, which + can be shifted from 0 to 1. This allows regulating the smoothness and high + sensitivity of the indicator. Sigma is another parameter that is responsible for + the shape of the curve coefficients. This moving average reduces lag of the data + in conjunction with smoothing to reduce noise. + + +Sources: + https://phemex.com/academy/what-is-arnaud-legoux-moving-averages + https://www.prorealcode.com/prorealtime-indicators/alma-arnaud-legoux-moving-average/ + + */ + +public class ALMA_Series : Single_TSeries_Indicator +{ + private readonly System.Collections.Generic.List _buffer = new(); + private readonly double[] _weight; + private double _norm; + private readonly double _offset, _sigma; + + public ALMA_Series(TSeries source, int period, double offset = 0.85, double sigma = 6.0, bool useNaN = false) + : base(source, period, useNaN) + { + _offset = offset; + _sigma = sigma; + _weight = new double[period]; + + if (this._data.Count > 0) { base.Add(this._data); } + } + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } + else { this._buffer.Add(TValue.v); } + if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); } + + if (this._buffer.Count <= _p) { calc_weights(); } + + double _weightedSum = 0; + for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; } + double _alma = _weightedSum / _norm; + + var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _alma); + base.Add(ret, update); + } + + private void calc_weights() + { + int _len = this._buffer.Count; + _norm = 0; + double _m = _offset * (_len - 1); + double _s = _len / _sigma; + for (int i = 0; i < _len; i++) + { + double _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s)); + _weight[i] = _wt; + _norm += _wt; + } + } +} diff --git a/Source/Indicators/DEMA_Series.cs b/Source/Trends/DEMA_Series.cs similarity index 91% rename from Source/Indicators/DEMA_Series.cs rename to Source/Trends/DEMA_Series.cs index 706196f0..d27fc288 100644 --- a/Source/Indicators/DEMA_Series.cs +++ b/Source/Trends/DEMA_Series.cs @@ -31,7 +31,6 @@ public class DEMA_Series : Single_TSeries_Indicator public override void Add((DateTime t, double v) TValue, bool update) { - if (update) { this._lastema1 = this._lastlastema1; @@ -53,15 +52,14 @@ public class DEMA_Series : Single_TSeries_Indicator for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } _sma /= this._buffer.Count; _ema1 = _ema2 = _sma; - } else { - _ema1 = TValue.v * this._k + this._lastema1 * this._k1m; - _ema2 = _ema1 * this._k + this._lastema2 * this._k1m; + _ema1 = (TValue.v * this._k) + (this._lastema1 * this._k1m); + _ema2 = (_ema1 * this._k) + (this._lastema2 * this._k1m); } - double _dema = 2 * _ema1 - _ema2; + double _dema = (2 * _ema1) - _ema2; this._lastlastema1 = this._lastema1; this._lastlastema2 = this._lastema2; this._lastema1 = _ema1; diff --git a/Source/Indicators/EMA_Series.cs b/Source/Trends/EMA_Series.cs similarity index 96% rename from Source/Indicators/EMA_Series.cs rename to Source/Trends/EMA_Series.cs index 98cf4a3e..62256fae 100644 --- a/Source/Indicators/EMA_Series.cs +++ b/Source/Trends/EMA_Series.cs @@ -52,7 +52,7 @@ public class EMA_Series : Single_TSeries_Indicator } else { - _ema = TValue.v * this._k + this._lastema * this._k1m; + _ema = (TValue.v * this._k) + (this._lastema * this._k1m); } this._lastlastema = this._lastema; diff --git a/Source/Indicators/HEMA_Series.cs b/Source/Trends/HEMA_Series.cs similarity index 100% rename from Source/Indicators/HEMA_Series.cs rename to Source/Trends/HEMA_Series.cs diff --git a/Source/Indicators/HMA_Series.cs b/Source/Trends/HMA_Series.cs similarity index 100% rename from Source/Indicators/HMA_Series.cs rename to Source/Trends/HMA_Series.cs diff --git a/Source/Indicators/JMA_Series.cs b/Source/Trends/JMA_Series.cs similarity index 100% rename from Source/Indicators/JMA_Series.cs rename to Source/Trends/JMA_Series.cs diff --git a/Source/Indicators/KAMA_Series.cs b/Source/Trends/KAMA_Series.cs similarity index 97% rename from Source/Indicators/KAMA_Series.cs rename to Source/Trends/KAMA_Series.cs index 2f46e25d..f27d08cd 100644 --- a/Source/Indicators/KAMA_Series.cs +++ b/Source/Trends/KAMA_Series.cs @@ -1,65 +1,65 @@ -namespace QuanTAlib; -using System; - -/* -KAMA: Kaufman's Adaptive Moving Average - Created in 1988 by American quantitative finance theorist Perry J. Kaufman and is known as - Kaufman's Adaptive Moving Average (KAMA). Even though the method was developed as early as 1972, - it was not until the popular book titled "Trading Systems and Methods" that it was made widely - available to the public. Unlike other conventional moving averages systems, the Kaufman's Adaptive - Moving Average, considers market volatility apart from price fluctuations. - - KAMAi = KAMAi - 1 + SC * ( price - KAMAi-1 ) - -Sources: - https://www.tutorialspoint.com/kaufman-s-adaptive-moving-average-kama-formula-and-how-does-it-work - https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/kaufmans-adaptive-moving-average-kama/ - https://www.technicalindicators.net/indicators-technical-analysis/152-kama-kaufman-adaptive-moving-average - -Remark: - If useNaN:true argument is provided, KAMA starts calculating values from [period] bar onwards. - Without useNaN argument (default setting), KAMA starts calculating values from bar 1 - and yields - slightly different results for the first 50 bars - and then converges with the other one. - - */ - -public class KAMA_Series : Single_TSeries_Indicator -{ - private readonly double _scFast, _scSlow; - private readonly System.Collections.Generic.List _buffer = new(); - private double _lastkama = double.NaN; - private double _lastlastkama; - - public KAMA_Series(TSeries source, int period, int fast = 2, int slow= 30, bool useNaN = false) : base(source, period, useNaN) { - _scFast = 2.0 / (fast+1); - _scSlow = 2.0 / (slow+1); - if (base._data.Count > 0) { base.Add(base._data); } - } - public override void Add((System.DateTime t, double v) TValue, bool update) - { - if (update){ - _buffer[_buffer.Count - 1] = TValue.v; - this._lastkama = this._lastlastkama; - } else { - _buffer.Add(TValue.v); - } - if (_buffer.Count > _p + 1) { _buffer.RemoveAt(0); } - double _kama = 0; - if (this.Count < this._p) { - for (int i = 0; i < this._buffer.Count; i++) { _kama += this._buffer[i]; } - _kama /= this._buffer.Count; - } else { - double _change = Math.Abs(_buffer[_buffer.Count - 1] - _buffer[(_buffer.Count > _p + 1) ? 1 : 0]); - double _sumpv = 0; - for (int i = 1; i < _buffer.Count; i++) - { _sumpv += Math.Abs(_buffer[(_buffer.Count > 0) ? i : 0] - _buffer[i - 1]); } - double _er = (_sumpv == 0) ? 0 : _change / _sumpv; - double _sc = (_er * (_scFast - _scSlow)) + _scSlow; - _kama = (_lastkama + (_sc * _sc * (TValue.v - _lastkama))); - } - _lastlastkama = _lastkama; - _lastkama = _kama; - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _kama); - base.Add(result, update); - } +namespace QuanTAlib; +using System; + +/* +KAMA: Kaufman's Adaptive Moving Average + Created in 1988 by American quantitative finance theorist Perry J. Kaufman and is known as + Kaufman's Adaptive Moving Average (KAMA). Even though the method was developed as early as 1972, + it was not until the popular book titled "Trading Systems and Methods" that it was made widely + available to the public. Unlike other conventional moving averages systems, the Kaufman's Adaptive + Moving Average, considers market volatility apart from price fluctuations. + + KAMAi = KAMAi - 1 + SC * ( price - KAMAi-1 ) + +Sources: + https://www.tutorialspoint.com/kaufman-s-adaptive-moving-average-kama-formula-and-how-does-it-work + https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/kaufmans-adaptive-moving-average-kama/ + https://www.technicalindicators.net/indicators-technical-analysis/152-kama-kaufman-adaptive-moving-average + +Remark: + If useNaN:true argument is provided, KAMA starts calculating values from [period] bar onwards. + Without useNaN argument (default setting), KAMA starts calculating values from bar 1 - and yields + slightly different results for the first 50 bars - and then converges with the other one. + + */ + +public class KAMA_Series : Single_TSeries_Indicator +{ + private readonly double _scFast, _scSlow; + private readonly System.Collections.Generic.List _buffer = new(); + private double _lastkama = double.NaN; + private double _lastlastkama; + + public KAMA_Series(TSeries source, int period, int fast = 2, int slow= 30, bool useNaN = false) : base(source, period, useNaN) { + _scFast = 2.0 / (fast+1); + _scSlow = 2.0 / (slow+1); + if (base._data.Count > 0) { base.Add(base._data); } + } + public override void Add((System.DateTime t, double v) TValue, bool update) + { + if (update){ + _buffer[_buffer.Count - 1] = TValue.v; + this._lastkama = this._lastlastkama; + } else { + _buffer.Add(TValue.v); + } + if (_buffer.Count > _p + 1) { _buffer.RemoveAt(0); } + double _kama = 0; + if (this.Count < this._p) { + for (int i = 0; i < this._buffer.Count; i++) { _kama += this._buffer[i]; } + _kama /= this._buffer.Count; + } else { + double _change = Math.Abs(_buffer[_buffer.Count - 1] - _buffer[(_buffer.Count > _p + 1) ? 1 : 0]); + double _sumpv = 0; + for (int i = 1; i < _buffer.Count; i++) + { _sumpv += Math.Abs(_buffer[(_buffer.Count > 0) ? i : 0] - _buffer[i - 1]); } + double _er = (_sumpv == 0) ? 0 : _change / _sumpv; + double _sc = (_er * (_scFast - _scSlow)) + _scSlow; + _kama = (_lastkama + (_sc * _sc * (TValue.v - _lastkama))); + } + _lastlastkama = _lastkama; + _lastkama = _kama; + var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _kama); + base.Add(result, update); + } } \ No newline at end of file diff --git a/Source/Indicators/MACD_Series.cs b/Source/Trends/MACD_Series.cs similarity index 100% rename from Source/Indicators/MACD_Series.cs rename to Source/Trends/MACD_Series.cs diff --git a/Source/Indicators/RMA_Series.cs b/Source/Trends/RMA_Series.cs similarity index 97% rename from Source/Indicators/RMA_Series.cs rename to Source/Trends/RMA_Series.cs index b0d28a94..a93accc1 100644 --- a/Source/Indicators/RMA_Series.cs +++ b/Source/Trends/RMA_Series.cs @@ -51,7 +51,7 @@ public class RMA_Series : Single_TSeries_Indicator } else { - _ema = TValue.v * _k + _lastema * _k1m; + _ema = (TValue.v * _k) + (_lastema * _k1m); } this._lastlastema = this._lastema; diff --git a/Source/Indicators/SMA_Series.cs b/Source/Trends/SMA_Series.cs similarity index 100% rename from Source/Indicators/SMA_Series.cs rename to Source/Trends/SMA_Series.cs diff --git a/Source/Indicators/SMMA_Series.cs b/Source/Trends/SMMA_Series.cs similarity index 100% rename from Source/Indicators/SMMA_Series.cs rename to Source/Trends/SMMA_Series.cs diff --git a/Source/Indicators/TEMA_Series.cs b/Source/Trends/TEMA_Series.cs similarity index 89% rename from Source/Indicators/TEMA_Series.cs rename to Source/Trends/TEMA_Series.cs index 6dfcbbb0..90aacfe2 100644 --- a/Source/Indicators/TEMA_Series.cs +++ b/Source/Trends/TEMA_Series.cs @@ -33,7 +33,6 @@ public class TEMA_Series : Single_TSeries_Indicator public override void Add((DateTime t, double v) TValue, bool update) { - if (update) { this._lastema1 = this._lastlastema1; @@ -59,12 +58,12 @@ public class TEMA_Series : Single_TSeries_Indicator } else { - _ema1 = TValue.v * this._k + this._lastema1 * this._k1m; - _ema2 = _ema1 * this._k + this._lastema2 * this._k1m; - _ema3 = _ema2 * this._k + this._lastema3 * this._k1m; + _ema1 = (TValue.v * this._k) + (this._lastema1 * this._k1m); + _ema2 = (_ema1 * this._k) + (this._lastema2 * this._k1m); + _ema3 = (_ema2 * this._k) + (this._lastema3 * this._k1m); } - double _tema = 3 * (_ema1 - _ema2) + _ema3; + double _tema = (3 * (_ema1 - _ema2)) + _ema3; this._lastlastema1 = this._lastema1; this._lastlastema2 = this._lastema2; diff --git a/Source/Trends/TRIMA_Series.cs b/Source/Trends/TRIMA_Series.cs new file mode 100644 index 00000000..78304982 --- /dev/null +++ b/Source/Trends/TRIMA_Series.cs @@ -0,0 +1,49 @@ +namespace QuanTAlib; +using System; + +/* +TRIMA: Triangular Moving Average + A weighted moving average where the shape of the weights are triangular and the greatest + weight is in the middle of the period, + +Sources: + https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triangular-moving-average-trima/ + +Remark: + trima = sma(sma(signal, n/2), n/2) + + */ + +public class TRIMA_Series : Single_TSeries_Indicator +{ + private readonly System.Collections.Generic.List _buffer1 = new(); + private readonly System.Collections.Generic.List _buffer2 = new(); + private readonly int _p1a, _p1b; + + public TRIMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + _p1a = (int) Math.Floor((period * 0.5) + 1); + _p1b = (int) Math.Ceiling(0.5 * period); + if (base._data.Count > 0) { base.Add(base._data); } + } + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + if (update) { _buffer1[_buffer1.Count - 1] = TValue.v; } else { _buffer1.Add(TValue.v); } + if (_buffer1.Count > this._p1b && this._p1b != 0) { _buffer1.RemoveAt(0); } + + double _sma1 = 0; + for (int i = 0; i < _buffer1.Count; i++) { _sma1 += _buffer1[i]; } + _sma1 /= this._buffer1.Count; + + if (update) { _buffer2[_buffer2.Count - 1] = _sma1; } else { _buffer2.Add(_sma1); } + if (_buffer2.Count > this._p1a && this._p1a != 0) { _buffer2.RemoveAt(0); } + + double _trima = 0; + for (int i = 0; i < _buffer2.Count; i++) { _trima += _buffer2[i]; } + _trima /= this._buffer2.Count; + + var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _trima); + base.Add(result, update); + } +} \ No newline at end of file diff --git a/Source/Indicators/WMA_Series.cs b/Source/Trends/WMA_Series.cs similarity index 100% rename from Source/Indicators/WMA_Series.cs rename to Source/Trends/WMA_Series.cs diff --git a/Source/Indicators/ZLEMA_Series.cs b/Source/Trends/ZLEMA_Series.cs similarity index 94% rename from Source/Indicators/ZLEMA_Series.cs rename to Source/Trends/ZLEMA_Series.cs index 657bfbc7..fdc53877 100644 --- a/Source/Indicators/ZLEMA_Series.cs +++ b/Source/Trends/ZLEMA_Series.cs @@ -1,72 +1,72 @@ -namespace QuanTAlib; -using System; - -/* -ZLEMA: Zero Lag Exponential Moving Average - The Zero lag exponential moving average (ZLEMA) indicator was created by John - Ehlers and Ric Way. - -The formula for a given N-Day period and for a given Data series is: - Lag = (Period-1)/2 - Ema Data = {Data+(Data-Data(Lag days ago)) - ZLEMA = EMA (EmaData,Period) - -Remark: - The idea is do a regular exponential moving average (EMA) calculation but on a - de-lagged data instead of doing it on the regular data. Data is de-lagged by - removing the data from "lag" days ago thus removing (or attempting to remove) - the cumulative lag effect of the moving average. - - */ - -public class ZLEMA_Series : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer = new(); - private readonly double _k, _k1m; - private double _lastema, _lastlastema; - - public ZLEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - this._k = 2.0 / (this._p + 1); - this._k1m = 1.0 - this._k; - this._lastema = this._lastlastema = double.NaN; - if (base._data.Count > 0) - { base.Add(base._data); } - } - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - int _lag = (int)((_p-1) * 0.5); - _lag = (this.Count-_lag < 0) ? 0 : this.Count-_lag; - double _zl = TValue.v + (TValue.v - _data[_lag].v); - - double _ema = 0; - if (update) - { this._lastema = this._lastlastema; } - if (this.Count < this._p) - { - if (update) - { this._buffer[this._buffer.Count - 1] = _zl; } - else - { - this._buffer.Add(_zl); - } - if (this._buffer.Count > this._p) - { this._buffer.RemoveAt(0); } - - for (int i = 0; i < this._buffer.Count; i++) - { _ema += this._buffer[i]; } - _ema /= this._buffer.Count; - } - else - { - _ema = _zl * this._k + this._lastema * this._k1m; - } - - this._lastlastema = this._lastema; - this._lastema = _ema; - - var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); - base.Add(ret, update); - } +namespace QuanTAlib; +using System; + +/* +ZLEMA: Zero Lag Exponential Moving Average + The Zero lag exponential moving average (ZLEMA) indicator was created by John + Ehlers and Ric Way. + +The formula for a given N-Day period and for a given Data series is: + Lag = (Period-1)/2 + Ema Data = {Data+(Data-Data(Lag days ago)) + ZLEMA = EMA (EmaData,Period) + +Remark: + The idea is do a regular exponential moving average (EMA) calculation but on a + de-lagged data instead of doing it on the regular data. Data is de-lagged by + removing the data from "lag" days ago thus removing (or attempting to remove) + the cumulative lag effect of the moving average. + + */ + +public class ZLEMA_Series : Single_TSeries_Indicator +{ + private readonly System.Collections.Generic.List _buffer = new(); + private readonly double _k, _k1m; + private double _lastema, _lastlastema; + + public ZLEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + this._k = 2.0 / (this._p + 1); + this._k1m = 1.0 - this._k; + this._lastema = this._lastlastema = double.NaN; + if (base._data.Count > 0) + { base.Add(base._data); } + } + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + int _lag = (int)((_p-1) * 0.5); + _lag = (this.Count-_lag < 0) ? 0 : this.Count-_lag; + double _zl = TValue.v + (TValue.v - _data[_lag].v); + + double _ema = 0; + if (update) + { this._lastema = this._lastlastema; } + if (this.Count < this._p) + { + if (update) + { this._buffer[this._buffer.Count - 1] = _zl; } + else + { + this._buffer.Add(_zl); + } + if (this._buffer.Count > this._p) + { this._buffer.RemoveAt(0); } + + for (int i = 0; i < this._buffer.Count; i++) + { _ema += this._buffer[i]; } + _ema /= this._buffer.Count; + } + else + { + _ema = (_zl * this._k) + (this._lastema * this._k1m); + } + + this._lastlastema = this._lastema; + this._lastema = _ema; + + var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); + base.Add(ret, update); + } } \ No newline at end of file diff --git a/Source/Indicators/ADL_Series.cs b/Source/Volatility/ADL_Series.cs similarity index 100% rename from Source/Indicators/ADL_Series.cs rename to Source/Volatility/ADL_Series.cs diff --git a/Source/Indicators/ADOSC_Series.cs b/Source/Volatility/ADOSC_Series.cs similarity index 100% rename from Source/Indicators/ADOSC_Series.cs rename to Source/Volatility/ADOSC_Series.cs diff --git a/Source/Indicators/ATRP_Series.cs b/Source/Volatility/ATRP_Series.cs similarity index 97% rename from Source/Indicators/ATRP_Series.cs rename to Source/Volatility/ATRP_Series.cs index a50916e6..2bb6f1b1 100644 --- a/Source/Indicators/ATRP_Series.cs +++ b/Source/Volatility/ATRP_Series.cs @@ -50,7 +50,7 @@ public class ATRP_Series : Single_TBars_Indicator for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } _ema /= this._buffer.Count; } - else { _ema = d.v * _k + _lastema * _k1m; } + else { _ema = (d.v * _k) + (_lastema * _k1m); } this._lastlastema = this._lastema; this._lastema = _ema; diff --git a/Source/Indicators/ATR_Series.cs b/Source/Volatility/ATR_Series.cs similarity index 97% rename from Source/Indicators/ATR_Series.cs rename to Source/Volatility/ATR_Series.cs index 70ec3c90..75740a1c 100644 --- a/Source/Indicators/ATR_Series.cs +++ b/Source/Volatility/ATR_Series.cs @@ -13,7 +13,6 @@ Sources: */ - public class ATR_Series : Single_TBars_Indicator { private readonly System.Collections.Generic.List _buffer = new(); @@ -53,7 +52,7 @@ public class ATR_Series : Single_TBars_Indicator for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } _ema /= this._buffer.Count; } - else { _ema = d.v * _k + _lastema * _k1m; } + else { _ema = (d.v * _k) + (_lastema * _k1m); } this._lastlastema = this._lastema; this._lastema = _ema; diff --git a/Source/Indicators/BBANDS_Series.cs b/Source/Volatility/BBANDS_Series.cs similarity index 100% rename from Source/Indicators/BBANDS_Series.cs rename to Source/Volatility/BBANDS_Series.cs diff --git a/Source/Indicators/RSI_Series.cs b/Source/Volatility/RSI_Series.cs similarity index 100% rename from Source/Indicators/RSI_Series.cs rename to Source/Volatility/RSI_Series.cs diff --git a/Source/Volume/OBV_Series.cs b/Source/Volume/OBV_Series.cs new file mode 100644 index 00000000..30758e9f --- /dev/null +++ b/Source/Volume/OBV_Series.cs @@ -0,0 +1,62 @@ +namespace QuanTAlib; +using System; + +/* +OBV: On-Balance Volume + On-balance volume (OBV) is a technical trading momentum indicator that uses volume flow to predict + changes in stock price. Joseph Granville first developed the OBV metric in the 1963 book + Granville's New Key to Stock Market Profits. + + | +volume; if close > close[previous] + OBV = OBV[previous] + | 0; if close = close[previous] + | -volume; if close < close[previous] + +Sources: + https://www.investopedia.com/terms/o/onbalancevolume.asp + https://www.tradingview.com/wiki/On_Balance_Volume_(OBV) + https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/on-balance-volume-obv/ + https://www.motivewave.com/studies/on_balance_volume.htm + +Note: + There is no consensus on what is the first OBV value in the series: + - TA-LIB uses the first volume: OBV[0] = volume[0] + - Skender stock library uses 0: OBV[0] = 0 + + */ + +public class OBV_Series : Single_TBars_Indicator +{ + private double _lastobv, _lastlastobv; + private double _lastclose, _lastlastclose; + public OBV_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) + { + this._lastobv = this._lastlastobv = 0; + this._lastclose = this._lastlastclose = 0; + if (_bars.Count > 0) { base.Add(_bars); } + } + + public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) + { + if (update) + { + this._lastobv = this._lastlastobv; + this._lastclose = this._lastlastclose; + } + + double _obv = this._lastobv; + if (TBar.c > this._lastclose) { _obv += TBar.v; } + if (TBar.c < this._lastclose) { _obv -= TBar.v; } + + // Unclear what the first value in OBV series is - currently set to volume[0] + // if (this.Count == 0) { _obv = 0; } + + this._lastlastobv = this._lastobv; + this._lastobv = _obv; + + this._lastlastclose = this._lastclose; + this._lastclose = TBar.c; + + var result = (TBar.t, (this.Count < this._p && this._NaN) ? double.NaN : _obv); + base.Add(result, update); + } +} diff --git a/Tests/Basics/TBars_Test.cs b/Tests/Basics/TBars_Test.cs index 67b0f121..c5f869a0 100644 --- a/Tests/Basics/TBars_Test.cs +++ b/Tests/Basics/TBars_Test.cs @@ -108,6 +108,5 @@ public class TBars_Test s.Add(DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false); Assert.Equal(s.Close.v, t.v); Assert.Equal(s.Close.Count, t.Count); - } } diff --git a/Tests/Basics/TSeries_Test.cs b/Tests/Basics/TSeries_Test.cs index 9ec5a85c..32357071 100644 --- a/Tests/Basics/TSeries_Test.cs +++ b/Tests/Basics/TSeries_Test.cs @@ -48,7 +48,6 @@ public class TSeries_Test TSeries t = s; Assert.Equal(5, (double)t); Assert.Equal(5, t.Count); - } [Fact] public void BroadcastingEvents() @@ -58,6 +57,5 @@ public class TSeries_Test s.Pub += t.Sub; s.Add(0.0, update: true); Assert.Equal(0.0, (double)t); - } } diff --git a/Tests/MovingAvg/ALMA_Test.cs b/Tests/MovingAvg/ALMA_Test.cs index fcf15738..75ac5eed 100644 --- a/Tests/MovingAvg/ALMA_Test.cs +++ b/Tests/MovingAvg/ALMA_Test.cs @@ -27,7 +27,5 @@ public class ALMA_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/MovingAvg/BBANDS_Test.cs b/Tests/MovingAvg/BBANDS_Test.cs index cd59b273..b843a361 100644 --- a/Tests/MovingAvg/BBANDS_Test.cs +++ b/Tests/MovingAvg/BBANDS_Test.cs @@ -52,7 +52,5 @@ public class BBANDS_Test Assert.Equal(a.Count, c.PercentB.Count); Assert.Equal(a.Count, c.Zscore.Count); Assert.Equal(a.Count, c.Bandwidth.Count); - } - } diff --git a/Tests/MovingAvg/DEMA_Test.cs b/Tests/MovingAvg/DEMA_Test.cs index 6d2a5a8c..0120be62 100644 --- a/Tests/MovingAvg/DEMA_Test.cs +++ b/Tests/MovingAvg/DEMA_Test.cs @@ -27,7 +27,5 @@ public class DEMA_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/MovingAvg/EMA_Test.cs b/Tests/MovingAvg/EMA_Test.cs index dc25bb3e..5d07b34d 100644 --- a/Tests/MovingAvg/EMA_Test.cs +++ b/Tests/MovingAvg/EMA_Test.cs @@ -27,7 +27,5 @@ public class EMA_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/MovingAvg/HEMA_Test.cs b/Tests/MovingAvg/HEMA_Test.cs index e68aeed6..8ad02f3c 100644 --- a/Tests/MovingAvg/HEMA_Test.cs +++ b/Tests/MovingAvg/HEMA_Test.cs @@ -27,7 +27,5 @@ public class HEMA_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/MovingAvg/HMA_Test.cs b/Tests/MovingAvg/HMA_Test.cs index 15c98600..0096e3a8 100644 --- a/Tests/MovingAvg/HMA_Test.cs +++ b/Tests/MovingAvg/HMA_Test.cs @@ -27,7 +27,5 @@ public class HMA_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/MovingAvg/JMA_Test.cs b/Tests/MovingAvg/JMA_Test.cs index c0df4051..27115e00 100644 --- a/Tests/MovingAvg/JMA_Test.cs +++ b/Tests/MovingAvg/JMA_Test.cs @@ -27,7 +27,5 @@ public class JMA_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/MovingAvg/KAMA_Test.cs b/Tests/MovingAvg/KAMA_Test.cs index 69e771c6..a7541b71 100644 --- a/Tests/MovingAvg/KAMA_Test.cs +++ b/Tests/MovingAvg/KAMA_Test.cs @@ -27,7 +27,5 @@ public class KAMA_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/MovingAvg/MACD_Test.cs b/Tests/MovingAvg/MACD_Test.cs index 61a3b46e..fd13cd88 100644 --- a/Tests/MovingAvg/MACD_Test.cs +++ b/Tests/MovingAvg/MACD_Test.cs @@ -27,7 +27,5 @@ public class MACD_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/MovingAvg/RMA_Test.cs b/Tests/MovingAvg/RMA_Test.cs index 396799bd..88becfac 100644 --- a/Tests/MovingAvg/RMA_Test.cs +++ b/Tests/MovingAvg/RMA_Test.cs @@ -27,7 +27,5 @@ public class RMA_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/MovingAvg/RSI_Test.cs b/Tests/MovingAvg/RSI_Test.cs index 7506cad7..3c89fab6 100644 --- a/Tests/MovingAvg/RSI_Test.cs +++ b/Tests/MovingAvg/RSI_Test.cs @@ -27,7 +27,5 @@ public class RSI_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/MovingAvg/SMA_Test.cs b/Tests/MovingAvg/SMA_Test.cs index a30a808a..d40e4842 100644 --- a/Tests/MovingAvg/SMA_Test.cs +++ b/Tests/MovingAvg/SMA_Test.cs @@ -27,7 +27,5 @@ public class SMA_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/MovingAvg/SMMA_Test.cs b/Tests/MovingAvg/SMMA_Test.cs index b6b1f79e..7c4fa58c 100644 --- a/Tests/MovingAvg/SMMA_Test.cs +++ b/Tests/MovingAvg/SMMA_Test.cs @@ -27,7 +27,5 @@ public class SMMA_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/MovingAvg/TEMA_Test.cs b/Tests/MovingAvg/TEMA_Test.cs index 03960e24..9553e346 100644 --- a/Tests/MovingAvg/TEMA_Test.cs +++ b/Tests/MovingAvg/TEMA_Test.cs @@ -27,7 +27,5 @@ public class TEMA_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/MovingAvg/WMA_Test.cs b/Tests/MovingAvg/WMA_Test.cs index d1839596..c3ab3569 100644 --- a/Tests/MovingAvg/WMA_Test.cs +++ b/Tests/MovingAvg/WMA_Test.cs @@ -27,7 +27,5 @@ public class WMA_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/MovingAvg/ZLEMA_Test.cs b/Tests/MovingAvg/ZLEMA_Test.cs index 634988cf..14af9e12 100644 --- a/Tests/MovingAvg/ZLEMA_Test.cs +++ b/Tests/MovingAvg/ZLEMA_Test.cs @@ -27,7 +27,5 @@ public class ZLEMA_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/BIAS_Test.cs b/Tests/Statistics/BIAS_Test.cs index e2f97115..c0370128 100644 --- a/Tests/Statistics/BIAS_Test.cs +++ b/Tests/Statistics/BIAS_Test.cs @@ -27,7 +27,5 @@ public class BIAS_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/ENTP_Test.cs b/Tests/Statistics/ENTP_Test.cs index e36f3e76..8fd086b7 100644 --- a/Tests/Statistics/ENTP_Test.cs +++ b/Tests/Statistics/ENTP_Test.cs @@ -27,7 +27,5 @@ public class KURT_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/KURT_Test.cs b/Tests/Statistics/KURT_Test.cs index 2a09b1d2..da1a1cfa 100644 --- a/Tests/Statistics/KURT_Test.cs +++ b/Tests/Statistics/KURT_Test.cs @@ -27,7 +27,5 @@ public class ENTP_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/LINREG_Test.cs b/Tests/Statistics/LINREG_Test.cs index c0370af1..89a8bb61 100644 --- a/Tests/Statistics/LINREG_Test.cs +++ b/Tests/Statistics/LINREG_Test.cs @@ -27,7 +27,5 @@ public class LINREG_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/MAD_Test.cs b/Tests/Statistics/MAD_Test.cs index 413b2eab..a2d3cb5a 100644 --- a/Tests/Statistics/MAD_Test.cs +++ b/Tests/Statistics/MAD_Test.cs @@ -27,7 +27,5 @@ public class MAD_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/MAPE_Test.cs b/Tests/Statistics/MAPE_Test.cs index ade998cd..64170230 100644 --- a/Tests/Statistics/MAPE_Test.cs +++ b/Tests/Statistics/MAPE_Test.cs @@ -27,7 +27,5 @@ public class MAPE_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/MAX_Test.cs b/Tests/Statistics/MAX_Test.cs index 772c8cb7..b12e205d 100644 --- a/Tests/Statistics/MAX_Test.cs +++ b/Tests/Statistics/MAX_Test.cs @@ -27,7 +27,5 @@ public class MAX_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/MED_Test.cs b/Tests/Statistics/MED_Test.cs index 9d1ec409..e9eafb15 100644 --- a/Tests/Statistics/MED_Test.cs +++ b/Tests/Statistics/MED_Test.cs @@ -27,7 +27,5 @@ public class MED_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/MIN_Test.cs b/Tests/Statistics/MIN_Test.cs index 38d41ca0..bebd4144 100644 --- a/Tests/Statistics/MIN_Test.cs +++ b/Tests/Statistics/MIN_Test.cs @@ -27,7 +27,5 @@ public class MIN_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/MSE_Test.cs b/Tests/Statistics/MSE_Test.cs index 310ad92b..379f9145 100644 --- a/Tests/Statistics/MSE_Test.cs +++ b/Tests/Statistics/MSE_Test.cs @@ -27,7 +27,5 @@ public class MSE_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/PSDEV_Test.cs b/Tests/Statistics/PSDEV_Test.cs index 503f9a6d..ce85da27 100644 --- a/Tests/Statistics/PSDEV_Test.cs +++ b/Tests/Statistics/PSDEV_Test.cs @@ -27,7 +27,5 @@ public class PSDEV_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/PVAR_Test .cs b/Tests/Statistics/PVAR_Test .cs index 67b4563d..67852e10 100644 --- a/Tests/Statistics/PVAR_Test .cs +++ b/Tests/Statistics/PVAR_Test .cs @@ -27,7 +27,5 @@ public class PVAR_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/SDEV_Test .cs b/Tests/Statistics/SDEV_Test .cs index 9b50f719..40c45af0 100644 --- a/Tests/Statistics/SDEV_Test .cs +++ b/Tests/Statistics/SDEV_Test .cs @@ -27,7 +27,5 @@ public class SDEV_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/SMAPE_Test.cs b/Tests/Statistics/SMAPE_Test.cs index 2ac0f171..4bef6373 100644 --- a/Tests/Statistics/SMAPE_Test.cs +++ b/Tests/Statistics/SMAPE_Test.cs @@ -27,7 +27,5 @@ public class SMAPE_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/VAR_Test.cs b/Tests/Statistics/VAR_Test.cs index 38384d58..db7e92f0 100644 --- a/Tests/Statistics/VAR_Test.cs +++ b/Tests/Statistics/VAR_Test.cs @@ -27,7 +27,5 @@ public class VAR_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Statistics/WMAPE_Test.cs b/Tests/Statistics/WMAPE_Test.cs index cd1a7276..36024557 100644 --- a/Tests/Statistics/WMAPE_Test.cs +++ b/Tests/Statistics/WMAPE_Test.cs @@ -27,7 +27,5 @@ public class WMAPE_Test Assert.Equal(a.Count, c.Count); a.Add(double.PositiveInfinity); Assert.Equal(a.Count, c.Count); - } - } diff --git a/Tests/Validations/Pandas_TA.cs b/Tests/Validations/Pandas_TA.cs index 38bffb2d..0fd37fdc 100644 --- a/Tests/Validations/Pandas_TA.cs +++ b/Tests/Validations/Pandas_TA.cs @@ -1,5 +1,3 @@ - - using Xunit; using System; using QuanTAlib; @@ -120,5 +118,4 @@ public class PandasTA Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); } */ - } \ No newline at end of file diff --git a/Tests/Validations/Skender_Stock.cs b/Tests/Validations/Skender_Stock.cs index 2ee8329d..05b06066 100644 --- a/Tests/Validations/Skender_Stock.cs +++ b/Tests/Validations/Skender_Stock.cs @@ -3,7 +3,6 @@ using QuanTAlib; using Skender.Stock.Indicators; using Xunit; - namespace Validation; public class Skender_Stock { @@ -14,7 +13,7 @@ public class Skender_Stock public Skender_Stock() { - this.bars = new(1000); + this.bars = new(Bars: 1, Volatility:0.7, Drift:0.0); this.period = this.rnd.Next(28) + 3; this.quotes = this.bars.Select( q => new Quote @@ -34,7 +33,7 @@ public class Skender_Stock SMA_Series QL = new(this.bars.Close, this.period, false); var SK = this.quotes.GetSma(this.period); - Assert.Equal(Math.Round((double)SK.Last().Sma!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -43,7 +42,7 @@ public class Skender_Stock EMA_Series QL = new(this.bars.Close, this.period, false); var SK = this.quotes.GetEma(this.period); - Assert.Equal(Math.Round((double)SK.Last().Ema!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Ema!, 6), Math.Round(QL.Last().v, 6)); } [Fact] public void WMA() @@ -51,7 +50,7 @@ public class Skender_Stock WMA_Series QL = new(this.bars.Close, this.period, false); var SK = this.quotes.GetWma(this.period); - Assert.Equal(Math.Round((double)SK.Last().Wma!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Wma!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -60,7 +59,7 @@ public class Skender_Stock DEMA_Series QL = new(this.bars.Close, this.period, false); var SK = this.quotes.GetDema(this.period); - Assert.Equal(Math.Round((double)SK.Last().Dema!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Dema!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -69,7 +68,7 @@ public class Skender_Stock TEMA_Series QL = new(this.bars.Close, this.period, false); var SK = this.quotes.GetTema(this.period); - Assert.Equal(Math.Round((double)SK.Last().Tema!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Tema!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -78,7 +77,7 @@ public class Skender_Stock MAD_Series QL = new(this.bars.Close, this.period, false); var SK = this.quotes.GetSmaAnalysis(this.period); - Assert.Equal(Math.Round((double)SK.Last().Mad!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Mad!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -87,7 +86,7 @@ public class Skender_Stock MAPE_Series QL = new(this.bars.Close, this.period, false); var SK = this.quotes.GetSmaAnalysis(this.period); - Assert.Equal(Math.Round((double)SK.Last().Mape!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Mape!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -96,7 +95,18 @@ public class Skender_Stock ATR_Series QL = new(this.bars, this.period, false); var SK = this.quotes.GetAtr(this.period); - Assert.Equal(Math.Round((double)SK.Last().Atr!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Atr!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] + public void OBV() + { + OBV_Series QL = new(this.bars, this.period, false); + var SK = this.quotes.GetObv(this.period); + + // adding volume[0] to OBV to pass the test and keep compatibility with TA-LIB + Assert.Equal(Math.Round((double)SK.Last().Obv!, 6) + Math.Round((double)this.quotes.First().Volume!, 6), + Math.Round(QL.Last().v, 6)); } [Fact] @@ -105,7 +115,7 @@ public class Skender_Stock ADL_Series QL = new(this.bars, false); var SK = this.quotes.GetAdl(); - Assert.Equal(Math.Round((double)SK.Last().Adl!, 6), Math.Round(QL.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().Adl!, 5), Math.Round(QL.Last().v, 5)); } [Fact] @@ -114,7 +124,7 @@ public class Skender_Stock CCI_Series QL = new(this.bars, this.period, false); var SK = this.quotes.GetCci(this.period); - Assert.Equal(Math.Round((double)SK.Last().Cci!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Cci!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -123,7 +133,7 @@ public class Skender_Stock ATRP_Series QL = new(this.bars, this.period, false); var SK = this.quotes.GetAtr(this.period); - Assert.Equal(Math.Round((double)SK.Last().Atrp!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Atrp!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -132,7 +142,7 @@ public class Skender_Stock KAMA_Series QL = new(this.bars.Close, this.period, useNaN: false); var SK = this.quotes.GetKama(this.period); - Assert.Equal(Math.Round((double)SK.Last().Kama!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Kama!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -141,7 +151,7 @@ public class Skender_Stock HMA_Series QL = new(this.bars.Close, this.period, useNaN: false); var SK = this.quotes.GetHma(this.period); - Assert.Equal(Math.Round((double)SK.Last().Hma!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Hma!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -150,7 +160,7 @@ public class Skender_Stock SMMA_Series QL = new(this.bars.Close, this.period, useNaN: false); var SK = this.quotes.GetSmma(this.period); - Assert.Equal(Math.Round((double)SK.Last().Smma!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Smma!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -159,8 +169,8 @@ public class Skender_Stock MACD_Series QL = new(this.bars.Close, 26,12,9, useNaN: false); var SK = this.quotes.GetMacd(12,26,9); - Assert.Equal(Math.Round((double)SK.Last().Macd!, 8), Math.Round(QL.Last().v, 8)); - Assert.Equal(Math.Round((double)SK.Last().Signal!, 8), Math.Round(QL.Signal.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Macd!, 6), Math.Round(QL.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().Signal!, 6), Math.Round(QL.Signal.Last().v, 6)); } [Fact] @@ -169,22 +179,21 @@ public class Skender_Stock BBANDS_Series QL = new(this.bars.Close, this.period, 2.0, useNaN: false); var SK = this.quotes.GetBollingerBands(this.period, 2.0); - Assert.Equal(Math.Round((double)SK.Last().Sma!, 8), Math.Round(QL.Mid.Last().v, 8)); - Assert.Equal(Math.Round((double)SK.Last().UpperBand!, 8), Math.Round(QL.Upper.Last().v, 8)); - Assert.Equal(Math.Round((double)SK.Last().LowerBand!, 8), Math.Round(QL.Lower.Last().v, 8)); - Assert.Equal(Math.Round((double)SK.Last().Width!, 8), Math.Round(QL.Bandwidth.Last().v, 8)); - Assert.Equal(Math.Round((double)SK.Last().PercentB!, 8), Math.Round(QL.PercentB.Last().v, 8)); - Assert.Equal(Math.Round((double)SK.Last().ZScore!, 8), Math.Round(QL.Zscore.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Mid.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().UpperBand!, 6), Math.Round(QL.Upper.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().LowerBand!, 6), Math.Round(QL.Lower.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().Width!, 6), Math.Round(QL.Bandwidth.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().PercentB!, 6), Math.Round(QL.PercentB.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().ZScore!, 6), Math.Round(QL.Zscore.Last().v, 6)); } - [Fact] public void RSI() { RSI_Series QL = new(this.bars.Close, this.period, useNaN: false); var SK = this.quotes.GetRsi(this.period); - Assert.Equal(Math.Round((double)SK.Last().Rsi!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Rsi!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -193,7 +202,7 @@ public class Skender_Stock ALMA_Series QL = new(this.bars.Close, this.period, useNaN: false); var SK = this.quotes.GetAlma(this.period); - Assert.Equal(Math.Round((double)SK.Last().Alma!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Alma!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -202,7 +211,7 @@ public class Skender_Stock SDEV_Series QL = new(this.bars.Close, this.period, useNaN: false); var SK = this.quotes.GetStdDev(this.period); - Assert.Equal(Math.Round((double)SK.Last().StdDev!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -211,10 +220,10 @@ public class Skender_Stock LINREG_Series QL = new(this.bars.Close, this.period, useNaN: false); var SK = this.quotes.GetSlope(this.period); - Assert.Equal(Math.Round((double)SK.Last().Slope!, 8), Math.Round(QL.Last().v, 8)); - Assert.Equal(Math.Round((double)SK.Last().Intercept!, 8), Math.Round(QL.Intercept.Last().v, 8)); - Assert.Equal(Math.Round((double)SK.Last().RSquared!, 8), Math.Round(QL.RSquared.Last().v, 8)); - Assert.Equal(Math.Round((double)SK.Last().StdDev!, 8), Math.Round(QL.StdDev.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Slope!, 6), Math.Round(QL.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().Intercept!, 6), Math.Round(QL.Intercept.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().RSquared!, 6), Math.Round(QL.RSquared.Last().v, 6)); + Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.StdDev.Last().v, 6)); } [Fact] @@ -223,7 +232,7 @@ public class Skender_Stock TR_Series QL = new(this.bars, useNaN: false); var SK = this.quotes.GetTr(); - Assert.Equal(Math.Round((double)SK.Last().Tr!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Tr!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -232,7 +241,7 @@ public class Skender_Stock TSeries QL = this.bars.HL2; var SK = this.quotes.GetBaseQuote(CandlePart.HL2); - Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -241,7 +250,7 @@ public class Skender_Stock TSeries QL = this.bars.OC2; var SK = this.quotes.GetBaseQuote(CandlePart.OC2); - Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -250,7 +259,7 @@ public class Skender_Stock TSeries QL = this.bars.HLC3; var SK = this.quotes.GetBaseQuote(CandlePart.HLC3); - Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -259,7 +268,7 @@ public class Skender_Stock TSeries QL = this.bars.OHL3; var SK = this.quotes.GetBaseQuote(CandlePart.OHL3); - Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -268,6 +277,6 @@ public class Skender_Stock TSeries QL = this.bars.OHLC4; var SK = this.quotes.GetBaseQuote(CandlePart.OHLC4); - Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); } } diff --git a/Tests/Validations/TA_LIB.cs b/Tests/Validations/TA_LIB.cs index 076a17d0..4680de66 100644 --- a/Tests/Validations/TA_LIB.cs +++ b/Tests/Validations/TA_LIB.cs @@ -18,7 +18,7 @@ public class TA_LIB public TA_LIB() { - this.bars = new(1000); + this.bars = new(5000); this.period = this.rnd.Next(28) + 3; this.TALIB = new double[this.bars.Count]; this.inopen = this.bars.Open.v.ToArray(); @@ -36,7 +36,7 @@ public class TA_LIB ADD_Series QL = new(this.bars.Open, this.bars.Close); Core.Add(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -45,7 +45,7 @@ public class TA_LIB SUB_Series QL = new(this.bars.Open, this.bars.Close); Core.Sub(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -54,7 +54,7 @@ public class TA_LIB MUL_Series QL = new(this.bars.Open, this.bars.Close); Core.Mult(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -63,7 +63,7 @@ public class TA_LIB DIV_Series QL = new(this.bars.Open, this.bars.Close); Core.Div(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -72,17 +72,25 @@ public class TA_LIB SDEV_Series QL = new(this.bars.Close, this.period, false); Core.StdDev(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } - [Fact] public void SMA() { SMA_Series QL = new(this.bars.Close, this.period, false); Core.Sma(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void TRIMA() + { + TRIMA_Series QL = new(this.bars.Close, this.period, false); + Core.Trima(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -91,7 +99,7 @@ public class TA_LIB EMA_Series QL = new(this.bars.Close, this.period, false); Core.Ema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -99,8 +107,8 @@ public class TA_LIB { WMA_Series QL = new(this.bars.Close, this.period, false); Core.Wma(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -109,7 +117,7 @@ public class TA_LIB DEMA_Series QL = new(this.bars.Close, this.period, false); Core.Dema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -118,7 +126,7 @@ public class TA_LIB TEMA_Series QL = new(this.bars.Close, this.period, false); Core.Tema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -127,7 +135,7 @@ public class TA_LIB MAX_Series QL = new(this.bars.Close, this.period, false); Core.Max(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -136,7 +144,7 @@ public class TA_LIB MIN_Series QL = new(this.bars.Close, this.period, false); Core.Min(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -145,7 +153,16 @@ public class TA_LIB ADL_Series QL = new(this.bars, false); Core.Ad(this.inhigh, this.inlow, this.inclose, this.involume, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + } + + [Fact] + public void OBV() + { + OBV_Series QL = new(this.bars, this.period, false); + Core.Obv(this.inclose, this.involume, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); + + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -154,7 +171,7 @@ public class TA_LIB ADOSC_Series QL = new(this.bars, false); Core.AdOsc(this.inhigh, this.inlow, this.inclose, this.involume, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -163,7 +180,7 @@ public class TA_LIB ATR_Series QL = new(this.bars, this.period, false); Core.Atr(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -172,7 +189,7 @@ public class TA_LIB CCI_Series QL = new(this.bars, this.period, false); Core.Cci(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -181,7 +198,7 @@ public class TA_LIB RSI_Series QL = new(this.bars.Close, this.period, false); Core.Rsi(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -190,7 +207,7 @@ public class TA_LIB TR_Series QL = new(this.bars, false); Core.TRange(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -200,8 +217,8 @@ public class TA_LIB double[] macdHist = new double[this.bars.Count]; MACD_Series QL = new(this.bars.Close, slow: 26, fast: 12, signal: 9, false); Core.Macd(this.inclose, 0, this.bars.Count - 1, outMacd: this.TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); - Assert.Equal(Math.Round(macdSignal[macdSignal.Length - outBegIdx - 1], 8), Math.Round(QL.Signal.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); + Assert.Equal(Math.Round(macdSignal[macdSignal.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Signal.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -212,21 +229,18 @@ public class TA_LIB double[] outLower = new double[this.bars.Count]; BBANDS_Series QL = new(this.bars.Close, period:26, multiplier:2.0, false); Core.Bbands(this.inclose, 0, this.bars.Count - 1, outRealUpperBand: outUpper, outRealMiddleBand: outMiddle, outRealLowerBand: outLower, out int outBegIdx, out _, optInTimePeriod:26, optInNbDevUp:2.0, optInNbDevDn:2.0); - Assert.Equal(Math.Round(outUpper[outUpper.Length - outBegIdx - 1], 7), Math.Round(QL.Upper.Last().v, 7)); - Assert.Equal(Math.Round(outMiddle[outMiddle.Length - outBegIdx - 1], 7), Math.Round(QL.Mid.Last().v, 7)); - Assert.Equal(Math.Round(outLower[outLower.Length - outBegIdx - 1], 7), Math.Round(QL.Lower.Last().v, 7)); - + Assert.Equal(Math.Round(outUpper[outUpper.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Upper.Last().v, 6, MidpointRounding.AwayFromZero)); + Assert.Equal(Math.Round(outMiddle[outMiddle.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Mid.Last().v, 6, MidpointRounding.AwayFromZero)); + Assert.Equal(Math.Round(outLower[outLower.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Lower.Last().v, 6, MidpointRounding.AwayFromZero)); } - - [Fact] public void HL2() { TSeries QL = this.bars.HL2; Core.MedPrice(this.inhigh, this.inlow, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -235,7 +249,7 @@ public class TA_LIB TSeries QL = this.bars.HLC3; Core.TypPrice(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -244,7 +258,7 @@ public class TA_LIB TSeries QL = this.bars.OHLC4; Core.AvgPrice(this.inopen, this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } [Fact] @@ -253,7 +267,6 @@ public class TA_LIB TSeries QL = this.bars.HLCC4; Core.WclPrice( this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); - Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); + Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero)); } - } diff --git a/docs/crossovers.ipynb b/docs/crossovers.ipynb index 0e185e25..304d3013 100644 --- a/docs/crossovers.ipynb +++ b/docs/crossovers.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 35, "metadata": { "dotnet_interactive": { "language": "csharp" @@ -20,15 +20,6 @@ }, "metadata": {}, "output_type": "display_data" - }, - { - "data": { - "text/markdown": [ - "Loading extensions from `Plotly.NET.Interactive.dll`" - ] - }, - "metadata": {}, - "output_type": "display_data" } ], "source": [ @@ -43,7 +34,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 40, "metadata": { "dotnet_interactive": { "language": "csharp" @@ -55,14 +46,14 @@ "outputs": [], "source": [ "Yahoo_Feed data = new(Symbol: \"MSFT\", Period: 200);\n", - "ZLEMA_Series calc1 = new(data.OHLC4,20,true);\n", - "HMA_Series calc2 = new(data.OHLC4,20, true);\n", - "HEMA_Series calc3 = new(data.OHLC4,20, true);" + "ZLEMA_Series calc1 = new(data.OHLC4,20);\n", + "HMA_Series calc2 = new(data.OHLC4,20);\n", + "HEMA_Series calc3 = new(data.OHLC4,20);" ] }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 41, "metadata": { "dotnet_interactive": { "language": "csharp" @@ -77,29 +68,29 @@ "text/html": [ "\n", "
\n", - "
\r\n", + "
\r\n", "\r\n", "\n", diff --git a/docs/readme.md b/docs/readme.md index d98f2c3b..ce7c2fcf 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -37,84 +37,91 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett | **BASIC TRANSFORMS** | **QuanTAlib** | **TA-LIB** | **Skender** | |--|:--:|:--:|:--:| -| ✔️ OC2 - (Open+Close)/2 |️ `.OC2` || ️`GetBaseQuote` | -| ⭐ HL2 - Median Price | `.HL2` | `MEDPRICE` | ️`GetBaseQuote` | -| ⭐ HLC3 - Typical Price | `.HLC3` | `TYPPRICE` || +| ✔️ OC2 - (Open+Close)/2 |️ `.OC2` || ️GetBaseQuote | +| ⭐ HL2 - Median Price | `.HL2` | MEDPRICE | ️GetBaseQuote | +| ⭐ HLC3 - Typical Price | `.HLC3` | TYPPRICE || | ✔️ OHL3 - (Open+High+Low)/3 | `.OHL3` ||| -| ⭐ OHLC4 - Average Price | `.OHLC4` | `AVGPRICE` |️ `GetBaseQuote` | -| ⭐ HLCC4 - Weighted Price | `.HLCC4` | `WCLPRICE` || -| ✔️ ZL - De-lagged price (Zero-Lag) | `ZL_Series` ||| -| ⭐ MAX - Max value | `MAX_Series` | `MAX` || -| ⛔ MID - Midpoint value || `MIDPOINT` || -| ⛔ MIDP - Midpoint price || `MIDPRICE` || -| ⭐ MIN - Min value | `MIN_Series` | `MIN` || -| ⭐ ADD - Addition | `ADD_Series` | `ADD` || -| ⭐ SUB - Subtraction | `SUB_Series` | `SUB` || -| ⭐ MUL - Multiplication | `MUL_Series` | `MUL` || -| ⭐ DIV - Division | `DIV_Series` | `DIV` || +| ⭐ OHLC4 - Average Price | `.OHLC4` | AVGPRICE |️ GetBaseQuote | +| ⭐ HLCC4 - Weighted Price | `.HLCC4` | WCLPRICE || +| ⭐ MAX - Max value | `MAX_Series` | MAX || +| ⭐ MIN - Min value | `MIN_Series` | MIN || +| ⛔ MID - Midpoint value || MIDPOINT || +| ⛔ MIDP - Midpoint price || MIDPRICE || +| ⛔ SUM - Summation || SUM || +| ⭐ ADD - Addition | `ADD_Series` | ADD || +| ⭐ SUB - Subtraction | `SUB_Series` | SUB || +| ⭐ MUL - Multiplication | `MUL_Series` | MUL || +| ⭐ DIV - Division | `DIV_Series` | DIV || ||||| | **STATISTICS & NUMERICAL ANALYSIS** | **QuanTAlib** | **TA-LIB** | **Skender** | -| ✔️ BIAS - Bias | BIAS_Series ||| +| ✔️ BIAS - Bias | `BIAS_Series` ||| | ⛔ CORREL - Pearson's Correlation Coefficient || CORREL | GetCorrelation | | ⛔ COVAR - Covariance ||| GetCorrelation | -| ✔️ ENTP - Entropy | ENTP_Series ||| -| ✔️ KURT - Kurtosis | KURT_Series ||| -| ⭐ LINREG - Linear Regression | LINREG_Series || GetSlope | -| ⭐ MAD - Mean Absolute Deviation | MAD_Series || GetSma | -| ⭐ MAPE - Mean Absolute Percent Error | MAPE_Series || GetSma | -| ✔️ MED - Median value | MED_Series ||| -| ✔️ MSE - Mean Squared Error | MSE_Series || GetSma | +| ✔️ ENTP - Entropy | `ENTP_Series` ||| +| ✔️ KURT - Kurtosis | `KURT_Series` ||| +| ⭐ LINREG - Linear Regression | `LINREG_Series` || GetSlope | +| ⭐ MAD - Mean Absolute Deviation | `MAD_Series` || GetSma | +| ⭐ MAPE - Mean Absolute Percent Error | `MAPE_Series` || GetSma | +| ✔️ MED - Median value | `MED_Series` ||| +| ✔️ MSE - Mean Squared Error | `MSE_Series` || GetSma | | ⛔ SKEW - Skewness |||| -| ⭐ SDEV - Standard Deviation (Volatility) | SDEV_Series ||| -| ✔️ SSDEV - Sample Standard Deviation | SSDEV_Series ||| -| ✔️ SMAPE - Symmetric Mean Absolute Percent Error | SMAPE_Series ||| -| ✔️ VAR - Population Variance | VAR_Series ||| -| ✔️ SVAR - Sample Variance | SVAR_Series ||| +| ⭐ SDEV - Standard Deviation (Volatility) | `SDEV_Series` | STDDEV || +| ✔️ SSDEV - Sample Standard Deviation | `SSDEV_Series` ||| +| ✔️ SMAPE - Symmetric Mean Absolute Percent Error | `SMAPE_Series` ||| +| ✔️ VAR - Population Variance | `VAR_Series` | VAR || +| ✔️ SVAR - Sample Variance | `SVAR_Series` ||| | ⛔ QUANT - Quantile |||| -| ✔️ WMAPE - Weighted Mean Absolute Percent Error | WMAPE_Series ||| +| ✔️ WMAPE - Weighted Mean Absolute Percent Error | `WMAPE_Series` ||| | ⛔ ZSCORE - Number of standard deviations from mean |||| ||||| | **TREND INDICATORS & AVERAGES** | **QuanTAlib** | **TA-LIB** | **Skender** | | ⛔ AFIRMA - Autoregressive Finite Impulse Response Moving Average |||| -| ⭐ ALMA - Arnaud Legoux Moving Average | ALMA_Series || GetAlma | +| ⭐ ALMA - Arnaud Legoux Moving Average | `ALMA_Series` || GetAlma | | ⛔ ARIMA - Autoregressive Integrated Moving Average |||| -| ⭐ DEMA - Double EMA Average | DEMA_Series | DEMA | GetDema | -| ⭐ EMA - Exponential Moving Average | EMA_Series || GetEma | +| ⭐ DEMA - Double EMA Average | `DEMA_Series` | DEMA | GetDema | +| ⭐ EMA - Exponential Moving Average | `EMA_Series` || GetEma | | ⛔ EPMA - Endpoint Moving Average ||| GetEpma | +| ⛔ FRAMA - Fractal Adaptive Moving Average |||| | ⛔ FWMA - Fibonacci's Weighted Moving Average |||| -| ✔️ HEMA - Hull/EMA Average | HEMA_Series ||| +| ⛔ HILO - Gann High-Low Activator |||| +| ✔️ HEMA - Hull/EMA Average | `HEMA_Series` ||| | ⛔ Hilbert Transform Instantaneous Trendline || HT_TRENDLINE | GetHtTrendline | -| ⭐ HMA - Hull Moving Average | HMA_Series || GetHma | +| ⭐ HMA - Hull Moving Average | `HMA_Series` || GetHma | | ⛔ HWMA - Holt-Winter Moving Average |||| -| ✔️ JMA - Jurik Moving Average | JMA_Series ||| -| ⭐ KAMA - Kaufman's Adaptive Moving Average | KAMA_Series | KAMA | GetKama | +| ✔️ JMA - Jurik Moving Average | `JMA_Series` ||| +| ⭐ KAMA - Kaufman's Adaptive Moving Average | `KAMA_Series` | KAMA | GetKama | +| ⛔ KDJ - KDJ Indicator (trend reversal) |||| | ⛔ LSMA - Least Squares Moving Average |||| -| ⭐ MACD - Moving Average Convergence/Divergence | MACD_Series | MACD | GetMacd | +| ⭐ MACD - Moving Average Convergence/Divergence | `MACD_Series` | MACD | GetMacd | | ⛔ MAMA - MESA Adaptive Moving Average || MAMA | GetMama | +| ⛔ MCGD - McGinley Dynamic |||| | ⛔ MMA - Modified Moving Average |||| | ⛔ PPMA - Pivot Point Moving Average |||| | ⛔ PWMA - Pascal's Weighted Moving Average |||| -| ✔️ RMA - WildeR's Moving Average | RMA__Series ||| +| ✔️ RMA - WildeR's Moving Average | `RMA_Series` ||| | ⛔ SINWMA - Sine Weighted Moving Average |||| -| ⭐ SMA - Simple Moving Average | SMA_Series ||| -| ⭐ SMMA - Smoothed Moving Average | SMMA_Series ||| +| ⭐ SMA - Simple Moving Average | `SMA_Series` | SMA | GetSma | +| ⭐ SMMA - Smoothed Moving Average | `SMMA_Series` ||| | ⛔ SSF - Ehler's Super Smoother Filter |||| | ⛔ SUP - Supertrend |||| | ⛔ SWMA - Symmetric Weighted Moving Average |||| -| ⛔ T3 - Tillson T3 Moving Average |||| -| ⭐ TEMA - Triple EMA Average | TEMA_Series ||| -| ⛔ TRIMA - Triangular Moving Average |||| +| ⛔ T3 - Tillson T3 Moving Average || T3 | GetT3 | +| ⭐ TEMA - Triple EMA Average | `TEMA_Series` | TEMA | GetTema | +| ⭐ TRIMA - Triangular Moving Average | `TRIMA_Series` | TRIMA || +| ⛔ TSF - Time Series Forecast || TSF || | ⛔ VIDYA - Variable Index Dynamic Average |||| -| ⭐ WMA - Weighted Moving Average | WMA_Series ||| -| ✔️ ZLEMA - Zero Lag EMA Average | ZLEMA_Series ||| +| ⛔ VOR - Vortex Indicator |||| +| ⭐ WMA - Weighted Moving Average | `WMA_Series` | WMA | GetWma | +| ✔️ ZLEMA - Zero Lag EMA Average | `ZLEMA_Series` ||| ||||| | **VOLATILITY INDICATORS** | **QuanTAlib** | **TA-LIB** | **Skender** | -| ⭐ ADL - Chaikin Accumulation Distribution Line | ADL_Series | AD | GetAdl | -| ⭐ ADOSC - Chaikin Accumulation Distribution Oscillator | ADOSC_Series | ADOSC| GetAdl | -| ⭐ ATR - Average True Range | ATR_Series | ATR | GetAtr | -| ⭐ ATRP - Average True Range Percent | ATRP_Series || GetAtr | -| ✔️ BETA - Beta coefficient || BETA | GetBeta | -| ⭐ BBANDS - Bollinger Bands® | BBANDS_Series | BBANDS | GetBollingerBands | +| ⭐ ADL - Chaikin Accumulation Distribution Line | `ADL_Series` | AD | GetAdl | +| ⭐ ADOSC - Chaikin Accumulation Distribution Oscillator | `ADOSC_Series` | ADOSC| GetAdl | +| ⭐ ATR - Average True Range | `ATR_Series` | ATR | GetAtr | +| ⭐ ATRP - Average True Range Percent | `ATRP_Series` || GetAtr | +| ⛔ BETA - Beta coefficient || BETA | GetBeta | +| ⭐ BBANDS - Bollinger Bands® | `BBANDS_Series` | BBANDS | GetBollingerBands | +| ⛔ CHAND - Chandelier Exit ||| GetChandelier | | ⛔ CRSI - Connor RSI ||| GetConnorsRsi | | ⛔ DON - Donchian Channels ||| GetDonchian | | ⛔ FCB - Fractal Chaos Bands ||| GetFcb | @@ -122,11 +129,12 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett | ⛔ ICH - Ichimoku ||| GetIchimoku | | ⛔ KEL - Keltner Channels ||| GetKeltner | | ⛔ NATR - Normalized Average True Range || NATR | GetAtr | -| ⭐ RSI - Relative Strength Index | RSI_Series || +| ⛔ CHN - Price Channel Indicator |||| +| ⭐ RSI - Relative Strength Index | `RSI_Series` | RSI | GetRsi | | ⛔ SAR - Parabolic Stop and Reverse || SAR | GetParabolicSar | -| ⛔ SRSI - Stochastic RSI |||| +| ⛔ SRSI - Stochastic RSI || STOCHRSI | GetStochRsi | | ⛔ STARC - Starc Bands |||| -| ⭐ TR - True Range | TR_Series ||| +| ⭐ TR - True Range | `TR_Series` | TRANGE | GetTr | | ⛔ UI - Ulcer Index |||| | ⛔ VSTOP - Volatility Stop |||| ||||| @@ -138,11 +146,11 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett | ⛔ APO - Absolute Price Oscillator || APO || | ⛔ AROON - Aroon oscillator || AROON | GetAroon | | ⛔ BOP - Balance of Power || BOP | GetBop | -| ⭐ CCI - Commodity Channel Index | CCI_Series | CCI | GetCci | +| ⭐ CCI - Commodity Channel Index | `CCI_Series` | CCI | GetCci | | ⛔ CFO - Chande Forcast Oscillator |||| -| ⛔ CMF - Chaikin Money Flow |||| | ⛔ CMO - Chande Momentum Oscillator || CMO | GetCmo | | ⛔ COG - Center of Gravity |||| +| ⛔ COPPOCK - Coppock Curve |||| | ⛔ CTI - Ehler's Correlation Trend Indicator |||| | ⛔ DPO - Detrended Price Oscillator ||| GetDpo | | ⛔ DMI - Directional Movement Index || DX | GetAdx | @@ -152,23 +160,28 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett | ⛔ KRI - Kairi Relative Index |||| | ⛔ KVO - Klinger Volume Oscillator |||| | ⛔ MFI - Money Flow Index || MFI | GetMfi | -| ⛔ ROC - Rate of Change (Momentum) || MOM | GetRoc | +| ⛔ MOM - Momentum || MOM || | ⛔ NVI - Negative Volume Index |||| | ⛔ PO - Price Oscillator |||| | ⛔ PPO - Percentage Price Oscillator || PPO || | ⛔ PMO - Price Momentum Oscillator |||| | ⛔ PVI - Positive Volume Index |||| +| ⛔ ROC - Rate of Change || MOM | GetRoc | | ⛔ RVGI - Relative Vigor Index |||| | ⛔ SMI - Stochastic Momentum Index |||| -| ⛔ STOCH - Stochastic Oscillator |||| -| ⛔ TRIX - 1-day ROC of TEMA |||| +| ⛔ STC - Schaff Trend Cycle |||| +| ⛔ STOCH - Stochastic Oscillator || STOCH | GetStoch | +| ⛔ TRIX - 1-day ROC of TEMA || TRIX | GetTrix | | ⛔ TSI - True Strength Index |||| -| ⛔ UO - Ultimate Oscillator |||| +| ⛔ UO - Ultimate Oscillator || ULTOSC | GetUltimate | +| ⛔ WILLR - Larry Williams' %R || WILLR | GetWilliamsR | | ⛔ WGAT - Williams Alligator |||| ||||| | **VOLUME INDICATORS** | **QuanTAlib** | **TA-LIB** | **Skender** | | ⛔ AOBV - Archer On-Balance Volume |||| -| ⛔ OBV - On-Balance Volume || OBV | GetObv | +| ⛔ CMF - Chaikin Money Flow |||| +| ⛔ EOM - Ease of Movement |||| +| ⭐ OBV - On-Balance Volume | `OBV_Series` | OBV | GetObv | | ⛔ PRS - Price Relative Strength ||| | ⛔ PVOL - Price-Volume |||| | ⛔ PVO - Percentage Volume Oscillator |||| @@ -177,17 +190,3 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett | ⛔ VP - Volume Profile |||| | ⛔ VWAP - Volume Weighted Average Price |||| | ⛔ VWMA - Volume Weighted Moving Average |||| -||||| -|**Unsorted** | **QuanTAlib** | **TA-LIB** | **Skender** | -| ⛔ CHN - Price Channel |||| -| ⛔ COPPOCK - Coppock Curve |||| -| ⛔ EOM - Ease of Movement |||| -| ⛔ HILO - Gann High-Low Activator |||| -| ⛔ HT - HT Trendline |||| -| ⛔ MCGD - McGinley Dynamic |||| -| ⛔ STC - Schaff Trend Cycle |||| -| ⛔ WILLR - Larry Williams' %R |||| -| ⛔ VOR - Vortex Indicator |||| -| ⛔ PVT - Pivot Points |||| -| ⛔ KDJ - KDJ Index |||| -| ⛔ CHAND - Chandelier Exit ||||