From 509b6dec02981bc8038df49941bdd9810b28a58f Mon Sep 17 00:00:00 2001 From: Miha Date: Tue, 19 Apr 2022 22:34:42 -0700 Subject: [PATCH] TR and ATR --- Docs/Comparing_w_TALIB.ipynb | 17 +++-- Docs/coverage.md | 3 +- Source/Basics/ADD_Series.cs | 11 +++- .../{Abstract_Indicators.cs => Abstracts.cs} | 15 ++++- Source/Basics/DIV_Series.cs | 10 ++- Source/{Statistics => Basics}/MAX_Series.cs | 18 +++--- Source/{Statistics => Basics}/MIN_Series.cs | 14 ++-- Source/Basics/MUL_Series.cs | 8 ++- Source/Basics/RND_Feed.cs | 16 +++-- Source/Basics/SUB_Series.cs | 9 ++- Source/Basics/TBars.cs | 10 ++- Source/Basics/TR_Series.cs | 38 +++++++++++ Source/Basics/TSeries.cs | 12 +++- Source/Indicators/ATRP_Series.cs | 64 +++++++++++++++++++ Source/Indicators/ATR_Series.cs | 63 ++++++++++++++++++ .../{MovingAvg => Indicators}/DEMA_Series.cs | 12 ++-- .../{MovingAvg => Indicators}/EMA_Series.cs | 21 +++--- .../{MovingAvg => Indicators}/HEMA_Series.cs | 13 ++-- .../{MovingAvg => Indicators}/HMA_Series.cs | 14 ++-- .../{MovingAvg => Indicators}/JMA_Series.cs | 22 ++++--- .../{MovingAvg => Indicators}/RMA_Series.cs | 15 ++--- .../{MovingAvg => Indicators}/SMA_Series.cs | 13 ++-- .../{MovingAvg => Indicators}/TEMA_Series.cs | 12 ++-- .../{MovingAvg => Indicators}/WMA_Series.cs | 10 +-- .../{MovingAvg => Indicators}/ZLEMA_Series.cs | 29 +++++---- Source/QuanTAlib.csproj | 2 +- Source/Statistics/BIAS_Series.cs | 17 +++-- Source/Statistics/ENTP_Series.cs | 15 +++-- Source/Statistics/KURT_Series.cs | 13 ++-- Source/Statistics/MAD_Series.cs | 15 ++--- Source/Statistics/MAPE_Series.cs | 18 +++--- Source/Statistics/MED_Series.cs | 27 ++++---- Source/Statistics/MSE_Series.cs | 15 ++--- Source/Statistics/PSDEV_Series.cs | 15 ++--- Source/Statistics/PVAR_Series.cs | 13 ++-- Source/Statistics/SDEV_Series.cs | 14 ++-- Source/Statistics/SMAPE_Series.cs | 13 ++-- Source/Statistics/VAR_Series.cs | 13 ++-- Source/Statistics/WMAPE_Series.cs | 13 ++-- Tests/Validations/Skender_Stock.cs | 18 ++++++ Tests/Validations/TA_LIB.cs | 34 +++++++--- 41 files changed, 488 insertions(+), 236 deletions(-) rename Source/Basics/{Abstract_Indicators.cs => Abstracts.cs} (88%) rename Source/{Statistics => Basics}/MAX_Series.cs (77%) rename Source/{Statistics => Basics}/MIN_Series.cs (92%) create mode 100644 Source/Basics/TR_Series.cs create mode 100644 Source/Indicators/ATRP_Series.cs create mode 100644 Source/Indicators/ATR_Series.cs rename Source/{MovingAvg => Indicators}/DEMA_Series.cs (91%) rename Source/{MovingAvg => Indicators}/EMA_Series.cs (77%) rename Source/{MovingAvg => Indicators}/HEMA_Series.cs (91%) rename Source/{MovingAvg => Indicators}/HMA_Series.cs (93%) rename Source/{MovingAvg => Indicators}/JMA_Series.cs (91%) rename Source/{MovingAvg => Indicators}/RMA_Series.cs (87%) rename Source/{MovingAvg => Indicators}/SMA_Series.cs (74%) rename Source/{MovingAvg => Indicators}/TEMA_Series.cs (92%) rename Source/{MovingAvg => Indicators}/WMA_Series.cs (89%) rename Source/{MovingAvg => Indicators}/ZLEMA_Series.cs (68%) diff --git a/Docs/Comparing_w_TALIB.ipynb b/Docs/Comparing_w_TALIB.ipynb index cf547f51..4f245ac7 100644 --- a/Docs/Comparing_w_TALIB.ipynb +++ b/Docs/Comparing_w_TALIB.ipynb @@ -15,7 +15,7 @@ { "data": { "text/html": [ - "
Installed Packages
  • QuantLib, 1.0.7
  • TALib.NETCore, 0.4.4
" + "
Installed Packages
  • QuanTAlib, 0.1.10-beta
  • TALib.NETCore, 0.4.4
" ] }, "metadata": {}, @@ -24,7 +24,7 @@ ], "source": [ "#r \"nuget: TALib.NETCore, 0.4.4\" \n", - "#r \"nuget:QuanTAlib\" \n", + "#r \"nuget: QuanTAlib, 0.1.10-beta\" \n", "\n", "using QuanTAlib;\n", "using TALib;\n" @@ -43,13 +43,12 @@ }, "outputs": [ { - "data": { - "text/html": [ - "
1394
" - ] - }, - "metadata": {}, - "output_type": "display_data" + "ename": "Error", + "evalue": "(1,1): error CS0246: The type or namespace name 'YAHOO_Feed' could not be found (are you missing a using directive or an assembly reference?)", + "output_type": "error", + "traceback": [ + "(1,1): error CS0246: The type or namespace name 'YAHOO_Feed' could not be found (are you missing a using directive or an assembly reference?)" + ] } ], "source": [ diff --git a/Docs/coverage.md b/Docs/coverage.md index 16fd465b..906d5d1c 100644 --- a/Docs/coverage.md +++ b/Docs/coverage.md @@ -42,7 +42,8 @@ | AFIRMA - Autoregressive Finite Impulse Response Moving Average ||||| | ALMA - Arnaud Legoux Moving Average |||✔️|✔️| | ARIMA - Autoregressive Integrated Moving Average ||||| -| ATR - Average True Range ||✔️|✔️|✔️| +| ATR - Average True Range |✔️|✔️|✔️|✔️| +| ATRP - Average True Range Percent |✔️||✔️|| | DEMA - Double EMA |✔️|✔️|✔️|✔️| | EMA - Exponential Moving Average |✔️|✔️|✔️|✔️| | EPMA - Endpoint Moving Average |||✔️|| diff --git a/Source/Basics/ADD_Series.cs b/Source/Basics/ADD_Series.cs index 7c6c1959..13cc8bb5 100644 --- a/Source/Basics/ADD_Series.cs +++ b/Source/Basics/ADD_Series.cs @@ -1,6 +1,13 @@ -// ADD - adding TSeries+TSeries together, or TSeries+double, or double+TSeries -using System; namespace QuanTAlib; +using System; + +/* +ADD - adding TSeries+TSeries together, or TSeries+double, or double+TSeries + +Remarks: + Most of scaffolding is packaged in abstracty class Pair_TSeries_Indicator. + + */ public class ADD_Series : Pair_TSeries_Indicator { diff --git a/Source/Basics/Abstract_Indicators.cs b/Source/Basics/Abstracts.cs similarity index 88% rename from Source/Basics/Abstract_Indicators.cs rename to Source/Basics/Abstracts.cs index 99e779a4..1233687c 100644 --- a/Source/Basics/Abstract_Indicators.cs +++ b/Source/Basics/Abstracts.cs @@ -1,6 +1,18 @@ namespace QuanTAlib; using System; +/* +Abstract classes with all scaffolding required to build indicators. + All abstracts support period, NaN, and all permutations of Add() methods. + Indicator classess need to implement: + - Chaining constructor (Abstract's constructor executes first) + - Default Add(value) class + - optional Add(series) bulk insert class (for optimization of historical analysis) + Single_TSeries_Indicator - one single-value TSeries in, one TSeries out. + Pair_TSeries_Indicator - Two TSeries in, one TSeries out. (includes simple semaphoring) + Single_TBars_Indicator - One OHLCV TBars in, one TSeries out. + + */ public abstract class Single_TSeries_Indicator : TSeries { protected readonly int _p; @@ -124,8 +136,9 @@ public abstract class Single_TBars_Indicator : TSeries protected readonly TBars _bars; // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN) - protected Single_TBars_Indicator(TBars source, bool useNaN) + protected Single_TBars_Indicator(TBars source, int period, bool useNaN) { + this._p = period; this._bars = source; this._NaN = useNaN; this._bars.Close.Pub += this.Sub; diff --git a/Source/Basics/DIV_Series.cs b/Source/Basics/DIV_Series.cs index 11dedb01..16069917 100644 --- a/Source/Basics/DIV_Series.cs +++ b/Source/Basics/DIV_Series.cs @@ -1,6 +1,12 @@ -// DIV - divide TSeries/TSeries , or TSeries/double, or double/TSeries -using System; namespace QuanTAlib; +using System; + +/* +DIV - divide TSeries/TSeries , or TSeries/double, or double/TSeries + +Remarks: + Most of scaffolding is packaged in abstracty class Pair_TSeries_Indicator. + */ public class DIV_Series : Pair_TSeries_Indicator { diff --git a/Source/Statistics/MAX_Series.cs b/Source/Basics/MAX_Series.cs similarity index 77% rename from Source/Statistics/MAX_Series.cs rename to Source/Basics/MAX_Series.cs index 150eacd8..38228eae 100644 --- a/Source/Statistics/MAX_Series.cs +++ b/Source/Basics/MAX_Series.cs @@ -1,20 +1,18 @@ namespace QuanTAlib; -/* -MAX - Maximum value in the given period in the series. - -If period = 0 => period = full length of the series - -*/ - using System; -using System.Collections.Generic; + +/* +MAX - Maximum value in the given period in the series. + If period = 0 => period = full length of the series + */ + public class MAX_Series : Single_TSeries_Indicator { public MAX_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) { if (base._data.Count > 0) { base.Add(base._data); } } - private readonly List _buffer = new(); + private readonly System.Collections.Generic.List _buffer = new(); public override void Add((DateTime t, double v) d, bool update) { @@ -24,7 +22,7 @@ public class MAX_Series : Single_TSeries_Indicator double _max = d.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; } var result = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _max); diff --git a/Source/Statistics/MIN_Series.cs b/Source/Basics/MIN_Series.cs similarity index 92% rename from Source/Statistics/MIN_Series.cs rename to Source/Basics/MIN_Series.cs index 408bd183..d2f66892 100644 --- a/Source/Statistics/MIN_Series.cs +++ b/Source/Basics/MIN_Series.cs @@ -1,12 +1,10 @@ -/* -MIN - Minimum value in the given period in the series. - -If period = 0 => period = full length of the series - -*/ - -using System; namespace QuanTAlib; +using System; + +/* +MIN - Minimum value in the given period in the series. + If period = 0 => period = full length of the series + */ public class MIN_Series : Single_TSeries_Indicator { diff --git a/Source/Basics/MUL_Series.cs b/Source/Basics/MUL_Series.cs index 0965543f..c1c573bd 100644 --- a/Source/Basics/MUL_Series.cs +++ b/Source/Basics/MUL_Series.cs @@ -1,6 +1,10 @@ -// MUL - multiply TSeries*TSeries together, or TSeries*double, or double*TSeries -using System; namespace QuanTAlib; +using System; + +/* +MUL - multiply TSeries*TSeries together, or TSeries*double, or double*TSeries + + */ public class MUL_Series : Pair_TSeries_Indicator { diff --git a/Source/Basics/RND_Feed.cs b/Source/Basics/RND_Feed.cs index 6c886d02..b7c42e27 100644 --- a/Source/Basics/RND_Feed.cs +++ b/Source/Basics/RND_Feed.cs @@ -1,20 +1,28 @@ -using System; namespace QuanTAlib; +using System; + +/* +Random Bars generator - used for testing, validation and fun + Returns 'bars' number of candles that follow common market movement. + volatility defines how 'jumpy' is the series of + startvalue defines beginning closing price that then guides the rest of series + + */ public class RND_Feed : TBars { - public RND_Feed(int days, double volatility = 0.05, double startvalue = 100.0) + public RND_Feed(int bars, double volatility = 0.05, double startvalue = 100.0) { Random rnd = new(); double c = startvalue; - for (int i = 0; i < days; i++) + 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 v = Math.Round(1000 * rnd.NextDouble(), 2); - this.Add(DateTime.Today.AddDays(i - days), o, h, l, c, v); + this.Add(DateTime.Today.AddDays(i - bars), o, h, l, c, v); } } } \ No newline at end of file diff --git a/Source/Basics/SUB_Series.cs b/Source/Basics/SUB_Series.cs index abf37a8a..88511f81 100644 --- a/Source/Basics/SUB_Series.cs +++ b/Source/Basics/SUB_Series.cs @@ -1,6 +1,11 @@ -// SUB - subtracting TSeries-TSeries, or TSeries-double, or double-TSeries -using System; namespace QuanTAlib; +using System; + +/* +SUB - subtracting TSeries-TSeries, or TSeries-double, or double-TSeries + + */ + public class SUB_Series : Pair_TSeries_Indicator { diff --git a/Source/Basics/TBars.cs b/Source/Basics/TBars.cs index 6e79174e..5502253d 100644 --- a/Source/Basics/TBars.cs +++ b/Source/Basics/TBars.cs @@ -1,7 +1,15 @@ 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)> { private readonly TSeries _open = new(); diff --git a/Source/Basics/TR_Series.cs b/Source/Basics/TR_Series.cs new file mode 100644 index 00000000..3b760851 --- /dev/null +++ b/Source/Basics/TR_Series.cs @@ -0,0 +1,38 @@ +namespace QuanTAlib; +using System; + +/* +TR: True Range + True Range was introduced by J. Welles Wilder in his book New Concepts in Technical Trading Systems. + It measures the daily range plus any gap from the closing price of the preceding day. + +Calculation: + d1 = ABS(High - Low) + d2 = ABS(High - Previous close) + d3 = ABS(Previous close - Low) + TR = MAX(d1,d2,d3) + +Sources: + https://www.macroption.com/true-range/ + + */ + +public class TR_Series : Single_TBars_Indicator +{ + private double _cm1 = double.NaN; + public TR_Series(TBars source, bool useNaN = false) : base(source, period:0, useNaN:useNaN) { + if (this._bars.Count > 0) { base.Add(this._bars); } + } + + public override void Add((DateTime t, double o, double h, double l, double c, double v) TValue, bool update = false) + { + if (_cm1 is double.NaN) { _cm1 = TValue.c; } + + double d1 = Math.Abs(TValue.h - TValue.l); + double d2 = Math.Abs(_cm1 - TValue.h); + double d3 = Math.Abs(_cm1 - TValue.l); + var ret = (TValue.t, (base.Count==0 && base._NaN) ? double.NaN : Math.Max(d1,Math.Max(d2,d3)) ); + base.Add(ret, update); + _cm1 = TValue.c; + } +} \ No newline at end of file diff --git a/Source/Basics/TSeries.cs b/Source/Basics/TSeries.cs index ff6f5315..2fcb13e9 100644 --- a/Source/Basics/TSeries.cs +++ b/Source/Basics/TSeries.cs @@ -1,8 +1,18 @@ namespace QuanTAlib; - using System; using System.Linq; +/* +TSeries is the cornerstone of all QuanTAlib classess. + TSeries is a single List of tuples (time, value) and contains several operators, casts, overloads + and other helpers that simplify usage of library. + Think of TSeries as an equivalent of Numpy array. + + - includes Length property (to mimic array's method) + - includes publishing and subscribing methods that attach to events + - uses Linq only for two transmutations - needs to be refactored out eventually (for speed) + + */ public class TSeries : System.Collections.Generic.List<(DateTime t, double v)> { // when asked for a (t,v) tuple, return the last (t,v) on the List diff --git a/Source/Indicators/ATRP_Series.cs b/Source/Indicators/ATRP_Series.cs new file mode 100644 index 00000000..af3f6bab --- /dev/null +++ b/Source/Indicators/ATRP_Series.cs @@ -0,0 +1,64 @@ +namespace QuanTAlib; +using System; + +/* +ATR: wildeR Moving Average + The average true range (ATR) is a price volatility indicator + showing the average price variation of assets within a given time period. + +Sources: + https://en.wikipedia.org/wiki/Average_true_range + https://www.tradingview.com/wiki/Average_True_Range_(ATR) + https://www.investopedia.com/terms/a/atr.asp + + */ + + +public class ATR_Series : Single_TBars_Indicator +{ + private readonly System.Collections.Generic.List _buffer = new(); + private readonly double _k, _k1m; + private double _lastema, _lastlastema, _lastcm1; + private double _cm1 = double.NaN; + + public ATR_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) + { + this._k = 1.0 / (double)(this._p); + this._k1m = 1.0 - this._k; + this._lastema = this._lastlastema = double.NaN; + 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 = false) + { + if (update) { + this._lastema = this._lastlastema; + this._cm1 = this._lastcm1; + } + + if (_cm1 is double.NaN) { _cm1 = TBar.c; } + double d1 = Math.Abs(TBar.h - TBar.l); + double d2 = Math.Abs(_cm1 - TBar.h); + double d3 = Math.Abs(_cm1 - TBar.l); + (DateTime t, double v)d = (TBar.t, Math.Max(d1,Math.Max(d2,d3))); //TR value for RMA below + _lastcm1 = _cm1; + _cm1 = TBar.c; + + double _ema = 0; + if (this.Count < this._p) + { + if (update) { _buffer[_buffer.Count - 1] = d.v; } + else { _buffer.Add(d.v); } + if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } + for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } + _ema /= this._buffer.Count; + } + else { _ema = d.v * _k + _lastema * _k1m; } + + this._lastlastema = this._lastema; + this._lastema = _ema; + + var ret = (d.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/ATR_Series.cs b/Source/Indicators/ATR_Series.cs new file mode 100644 index 00000000..ebcec9b8 --- /dev/null +++ b/Source/Indicators/ATR_Series.cs @@ -0,0 +1,63 @@ +namespace QuanTAlib; +using System; + +/* +ATRP: Average True Range Percent + Average True Range Percent is (ATR/Close Price)*100. + This normalizes so it can be compared to other stocks. + +Sources: + https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/atrp + + */ + +public class ATRP_Series : Single_TBars_Indicator +{ + private readonly System.Collections.Generic.List _buffer = new(); + private readonly double _k, _k1m; + private double _lastema, _lastlastema, _lastcm1; + private double _cm1 = double.NaN; + + public ATRP_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) + { + this._k = 1.0 / (double)(this._p); + this._k1m = 1.0 - this._k; + this._lastema = this._lastlastema = double.NaN; + 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 = false) + { + if (update) { + this._lastema = this._lastlastema; + this._cm1 = this._lastcm1; + } + + if (_cm1 is double.NaN) { _cm1 = TBar.c; } + double d1 = Math.Abs(TBar.h - TBar.l); + double d2 = Math.Abs(_cm1 - TBar.h); + double d3 = Math.Abs(_cm1 - TBar.l); + (DateTime t, double v)d = (TBar.t, Math.Max(d1,Math.Max(d2,d3))); //TR value for RMA below + _lastcm1 = _cm1; + _cm1 = TBar.c; + + double _ema = 0; + if (this.Count < this._p) + { + if (update) { _buffer[_buffer.Count - 1] = d.v; } + else { _buffer.Add(d.v); } + if (_buffer.Count > this._p) { _buffer.RemoveAt(0); } + for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } + _ema /= this._buffer.Count; + } + else { _ema = d.v * _k + _lastema * _k1m; } + + this._lastlastema = this._lastema; + this._lastema = _ema; + + double _atrp = 100 * (_ema / TBar.c); + + var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atrp); + base.Add(ret, update); + } +} \ No newline at end of file diff --git a/Source/MovingAvg/DEMA_Series.cs b/Source/Indicators/DEMA_Series.cs similarity index 91% rename from Source/MovingAvg/DEMA_Series.cs rename to Source/Indicators/DEMA_Series.cs index 1d740254..41cdcbae 100644 --- a/Source/MovingAvg/DEMA_Series.cs +++ b/Source/Indicators/DEMA_Series.cs @@ -1,8 +1,9 @@ namespace QuanTAlib; +using System; -/** +/* DEMA: Double Exponential Moving Average -DEMA uses EMA(EMA()) to calculate smoother Exponential moving average. + DEMA uses EMA(EMA()) to calculate smoother Exponential moving average. Sources: https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/double-exponential-moving-average-dema/ @@ -11,13 +12,12 @@ Remark: ema1 = EMA(close, length) ema2 = EMA(ema1, length) DEMA = 2 * ema1 - ema2 -**/ -using System; -using System.Collections.Generic; + */ + public class DEMA_Series : Single_TSeries_Indicator { - private readonly List _buffer = new(); + private readonly System.Collections.Generic.List _buffer = new(); private readonly double _k, _k1m; private double _lastema1, _lastlastema1; private double _lastema2, _lastlastema2; diff --git a/Source/MovingAvg/EMA_Series.cs b/Source/Indicators/EMA_Series.cs similarity index 77% rename from Source/MovingAvg/EMA_Series.cs rename to Source/Indicators/EMA_Series.cs index a1ba2c14..2d53b02e 100644 --- a/Source/MovingAvg/EMA_Series.cs +++ b/Source/Indicators/EMA_Series.cs @@ -1,26 +1,27 @@ namespace QuanTAlib; +using System; -/** +/* EMA: Exponential Moving Average + EMA needs very short history buffer and calculates the EMA value using just the + previous EMA value. The weight of the new datapoint (k) is k = 2 / (period-1) -EMA needs very short history buffer and calculates the EMA value using just the -previous EMA value. The weight of the new datapoint (k) is k = 2 / (period-1) Sources: https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages https://www.investopedia.com/ask/answers/122314/what-exponential-moving-average-ema-formula-and-how-ema-calculated.asp https://blog.fugue88.ws/archives/2017-01/The-correct-way-to-start-an-Exponential-Moving-Average-EMA + Issues: There is no consensus what the first EMA value should be - a zero, a first -datapoint, or an average of the initial Period bars. All three starting methods -converge within 20+ bars to the same moving average. Most implementations (including this one) -use SMA() for the first Period bars as a seeding value for EMA. -**/ + datapoint, or an average of the initial Period bars. All three starting methods + converge within 20+ bars to the same moving average. Most implementations (including this one) + use SMA() for the first Period bars as a seeding value for EMA. + + */ -using System; -using System.Collections.Generic; public class EMA_Series : Single_TSeries_Indicator { - private readonly List _buffer = new(); + private readonly System.Collections.Generic.List _buffer = new(); private readonly double _k, _k1m; private double _lastema, _lastlastema; diff --git a/Source/MovingAvg/HEMA_Series.cs b/Source/Indicators/HEMA_Series.cs similarity index 91% rename from Source/MovingAvg/HEMA_Series.cs rename to Source/Indicators/HEMA_Series.cs index 3ffe260b..ac6a2f78 100644 --- a/Source/MovingAvg/HEMA_Series.cs +++ b/Source/Indicators/HEMA_Series.cs @@ -1,16 +1,17 @@ -using System; -namespace QuanTAlib; +namespace QuanTAlib; +using System; -/** +/* HEMA: Hull-EMA Moving Average -Modified HUll Moving Average; instead of using WMA (Weighted MA) for a -calculation, HEMA uses EMA for Hull's formula: + Modified HUll Moving Average; instead of using WMA (Weighted MA) for acalculation, + HEMA uses EMA for Hull's formula: EMA1 = EMA(n/2) of price - where k = 4/(n/2 +1) EMA2 = EMA(n) of price - where k = 3/(n+1) Raw HMA = (2 * EMA1) - EMA2 EMA3 = EMA(sqrt(n)) of Raw HMA - where k = 2/(sqrt(n)+1) -**/ + + */ public class HEMA_Series : Single_TSeries_Indicator { diff --git a/Source/MovingAvg/HMA_Series.cs b/Source/Indicators/HMA_Series.cs similarity index 93% rename from Source/MovingAvg/HMA_Series.cs rename to Source/Indicators/HMA_Series.cs index 41250bbe..e620b2f8 100644 --- a/Source/MovingAvg/HMA_Series.cs +++ b/Source/Indicators/HMA_Series.cs @@ -1,19 +1,21 @@ -using System; -namespace QuanTAlib; +namespace QuanTAlib; +using System; -/** +/* HMA: Hull Moving Average -Developed by Alan Hull, an extremely fast and smooth moving average; almost -eliminates lag altogether and manages to improve smoothing at the same time. + Developed by Alan Hull, an extremely fast and smooth moving average; almost + eliminates lag altogether and manages to improve smoothing at the same time. Sources: https://alanhull.com/hull-moving-average https://school.stockcharts.com/doku.php?id=technical_indicators:hull_moving_average + WMA1 = WMA(n/2) of price WMA2 = WMA(n) of price Raw HMA = (2 * WMA1) - WMA2 HMA = WMA(sqrt(n)) of Raw HMA -**/ + + */ public class HMA_Series : TSeries { diff --git a/Source/MovingAvg/JMA_Series.cs b/Source/Indicators/JMA_Series.cs similarity index 91% rename from Source/MovingAvg/JMA_Series.cs rename to Source/Indicators/JMA_Series.cs index 2e0c4789..2cf373b9 100644 --- a/Source/MovingAvg/JMA_Series.cs +++ b/Source/Indicators/JMA_Series.cs @@ -1,11 +1,11 @@ -using System; -namespace QuanTAlib; +namespace QuanTAlib; +using System; -/** +/* JMA: Jurik Moving Average -Mark Jurik's Moving Average (JMA) attempts to eliminate noise to see the -underlying activity. It has extremely low lag, is very smooth and is responsive -to market gaps. + Mark Jurik's Moving Average (JMA) attempts to eliminate noise to see the + underlying activity. It has extremely low lag, is very smooth and is responsive + to market gaps. Sources: https://c.mql5.com/forextsd/forum/164/jurik_1.pdf @@ -13,10 +13,12 @@ Sources: Issues: Real JMA algorithm is not published and this formula is derived through -deduction and reverse analysis of JMA behavior. It is really close, but not -exact - published JMA tests against JMA.CSV fail with small deviation. The -original algo is slightly different, yet this approximation is close enough. -**/ + deduction and reverse analysis of JMA behavior. It is really close, but not + exact - published JMA tests against JMA.CSV fail with small deviation. The + original algo is slightly different, yet this approximation is close enough. + + */ + public class JMA_Series : Single_TSeries_Indicator { private readonly System.Collections.Generic.List vbuffer10; diff --git a/Source/MovingAvg/RMA_Series.cs b/Source/Indicators/RMA_Series.cs similarity index 87% rename from Source/MovingAvg/RMA_Series.cs rename to Source/Indicators/RMA_Series.cs index 5e28083b..220acc23 100644 --- a/Source/MovingAvg/RMA_Series.cs +++ b/Source/Indicators/RMA_Series.cs @@ -1,12 +1,13 @@ namespace QuanTAlib; +using System; -/** +/* RMA: wildeR Moving Average + J. Welles Wilder introduced RMA as an alternative to EMA. RMA's weight (k) is + set as 1/period, giving less weight to the new data compared to EMA. -J. Welles Wilder introduced RMA as an alternative to EMA. RMA's weight (k) is -set as 1/period, giving less weight to the new data compared to EMA. Sources: +Sources: https://archive.org/details/newconceptsintec00wild/page/23/mode/2up - https://tlc.thinkorswim.com/center/reference/Tech-Indicators/studies-library/V-Z/WildersSmoothing https://www.incrediblecharts.com/indicators/wilder_moving_average.php @@ -15,13 +16,11 @@ Issues: pandas.ewm().mean() and returns incorrect first (period) of bars compared to published formula. This implementation passess the validation test in Wilder's book. -**/ + */ -using System; -using System.Collections.Generic; public class RMA_Series : Single_TSeries_Indicator { - private readonly List _buffer = new(); + private readonly System.Collections.Generic.List _buffer = new(); private readonly double _k, _k1m; private double _lastema, _lastlastema; diff --git a/Source/MovingAvg/SMA_Series.cs b/Source/Indicators/SMA_Series.cs similarity index 74% rename from Source/MovingAvg/SMA_Series.cs rename to Source/Indicators/SMA_Series.cs index bc6d143c..6dbc3064 100644 --- a/Source/MovingAvg/SMA_Series.cs +++ b/Source/Indicators/SMA_Series.cs @@ -1,17 +1,20 @@ namespace QuanTAlib; +using System; -/** +/* SMA: Simple Moving Average -The weights are equally distributed across the period, resulting in a mean() of -the data within the period/ + The weights are equally distributed across the period, resulting in a mean() of + the data within the period/ Sources: https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/simple-moving-average-sma/ https://stats.stackexchange.com/a/24739 Remark: - This calc doesn't use LINQ or SUM() or any of iterative methods. -**/ + This calc doesn't use LINQ or SUM() or any of (slow) iterative methods. It is not as fast as TA-LIB + implementation, but it does allow incremental additions of inputs and real-time calculations of SMA() + + */ public class SMA_Series : Single_TSeries_Indicator { diff --git a/Source/MovingAvg/TEMA_Series.cs b/Source/Indicators/TEMA_Series.cs similarity index 92% rename from Source/MovingAvg/TEMA_Series.cs rename to Source/Indicators/TEMA_Series.cs index 7fb9e8e4..5439f7b4 100644 --- a/Source/MovingAvg/TEMA_Series.cs +++ b/Source/Indicators/TEMA_Series.cs @@ -1,8 +1,9 @@ namespace QuanTAlib; +using System; -/** +/* TEMA: Triple Exponential Moving Average -TEMA uses EMA(EMA(EMA())) to calculate less laggy Exponential moving average. + TEMA uses EMA(EMA(EMA())) to calculate less laggy Exponential moving average. Sources: https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triple-exponential-moving-average-tema/ @@ -12,13 +13,12 @@ Remark: ema2 = EMA(ema1, length) ema3 = EMA(ema2, length) TEMA = 3 * (ema1 - ema2) + ema3 -**/ -using System; -using System.Collections.Generic; + */ + public class TEMA_Series : Single_TSeries_Indicator { - private readonly List _buffer = new(); + private readonly System.Collections.Generic.List _buffer = new(); private readonly double _k, _k1m; private double _lastema1, _lastlastema1; private double _lastema2, _lastlastema2; diff --git a/Source/MovingAvg/WMA_Series.cs b/Source/Indicators/WMA_Series.cs similarity index 89% rename from Source/MovingAvg/WMA_Series.cs rename to Source/Indicators/WMA_Series.cs index 20ec89ef..4c63bde0 100644 --- a/Source/MovingAvg/WMA_Series.cs +++ b/Source/Indicators/WMA_Series.cs @@ -1,14 +1,16 @@ namespace QuanTAlib; +using System; -/** +/* WMA: (linearly) Weighted Moving Average -The weights are linearly decreasing over the period and the most recent data has -the heaviest weight. + The weights are linearly decreasing over the period and the most recent data has + the heaviest weight. Sources: https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/weighted-moving-average-wma/ https://www.technicalindicators.net/indicators-technical-analysis/83-moving-averages-simple-exponential-weighted -**/ + + */ public class WMA_Series : Single_TSeries_Indicator { diff --git a/Source/MovingAvg/ZLEMA_Series.cs b/Source/Indicators/ZLEMA_Series.cs similarity index 68% rename from Source/MovingAvg/ZLEMA_Series.cs rename to Source/Indicators/ZLEMA_Series.cs index 8370b625..9ae072ae 100644 --- a/Source/MovingAvg/ZLEMA_Series.cs +++ b/Source/Indicators/ZLEMA_Series.cs @@ -1,22 +1,23 @@ -using System; -namespace QuanTAlib; +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 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) + Lag = (Period-1)/2 + Ema Data = {Data+(Data-Data(Lag days ago)) + ZLEMA = EMA (EmaData,Period) -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. -**/ +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 { diff --git a/Source/QuanTAlib.csproj b/Source/QuanTAlib.csproj index ae809740..2d29fbca 100644 --- a/Source/QuanTAlib.csproj +++ b/Source/QuanTAlib.csproj @@ -1,6 +1,6 @@  - 0.1.10-beta + 0.1.11 QuanTAlib Library of Technical Indicators for .NET diff --git a/Source/Statistics/BIAS_Series.cs b/Source/Statistics/BIAS_Series.cs index 26427a5c..3fb543b7 100644 --- a/Source/Statistics/BIAS_Series.cs +++ b/Source/Statistics/BIAS_Series.cs @@ -1,18 +1,17 @@ -/** - BIAS: Rate of change between the source and a moving average. +namespace QuanTAlib; +using System; - Bias is a statistical term which means a systematic deviation from the actual value. +/* +BIAS: Rate of change between the source and a moving average. + Bias is a statistical term which means a systematic deviation from the actual value. - BIAS = (close - SMA) / SMA +BIAS = (close - SMA) / SMA = (close / SMA) - 1 Sources: - https://en.wikipedia.org/wiki/Bias_of_an_estimator + https://en.wikipedia.org/wiki/Bias_of_an_estimator -**/ - -using System; -namespace QuanTAlib; + */ public class BIAS_Series : Single_TSeries_Indicator { diff --git a/Source/Statistics/ENTP_Series.cs b/Source/Statistics/ENTP_Series.cs index f1d64cfd..d39c58cd 100644 --- a/Source/Statistics/ENTP_Series.cs +++ b/Source/Statistics/ENTP_Series.cs @@ -1,8 +1,10 @@ -/** -ENTP: Entropy +namespace QuanTAlib; +using System; -Introduced by Claude Shannon in 1948, entropy measures the unpredictability -of the data, or equivalently, of its average information. +/* +ENTP: Entropy + Introduced by Claude Shannon in 1948, entropy measures the unpredictability + of the data, or equivalently, of its average information. Calculation: P = close / Σ(close) @@ -12,9 +14,8 @@ Sources: https://en.wikipedia.org/wiki/Entropy_(information_theory) https://math.stackexchange.com/questions/3428693/how-to-calculate-entropy-from-a-set-of-correlated-samples -**/ -namespace QuanTAlib; -using System; + */ + public class ENTP_Series : Single_TSeries_Indicator { public ENTP_Series(TSeries source, int period, double logbase = 2.0, bool useNaN = false) : base(source, period, useNaN) diff --git a/Source/Statistics/KURT_Series.cs b/Source/Statistics/KURT_Series.cs index cc5a1c63..2dc265d2 100644 --- a/Source/Statistics/KURT_Series.cs +++ b/Source/Statistics/KURT_Series.cs @@ -1,6 +1,8 @@ -/** -KURT: Kurtosis of population +namespace QuanTAlib; +using System; +/* +KURT: Kurtosis of population Kurtosis characterizes the relative peakedness or flatness of a distribution compared with the normal distribution. Positive kurtosis indicates a relatively peaked distribution. Negative kurtosis indicates a relatively flat distribution. @@ -19,12 +21,7 @@ Sources: https://en.wikipedia.org/wiki/Kurtosis https://stats.oarc.ucla.edu/other/mult-pkg/faq/general/faq-whats-with-the-different-formulas-for-kurtosis/ -**/ - -using System; -namespace QuanTAlib; - -// https://stats.oarc.ucla.edu/other/mult-pkg/faq/general/faq-whats-with-the-different-formulas-for-kurtosis/ + */ public class KURT_Series : Single_TSeries_Indicator { diff --git a/Source/Statistics/MAD_Series.cs b/Source/Statistics/MAD_Series.cs index 72723afe..30f1e0af 100644 --- a/Source/Statistics/MAD_Series.cs +++ b/Source/Statistics/MAD_Series.cs @@ -1,8 +1,10 @@ -/** -MAD: Mean Absolute Deviation +namespace QuanTAlib; +using System; -Also known as AAD - Average Absolute Deviation, to differentiate it from Median Absolute Deviation -MAD defines the degree of variation across the series. +/* +MAD: Mean Absolute Deviation + Also known as AAD - Average Absolute Deviation, to differentiate it from Median Absolute Deviation + MAD defines the degree of variation across the series. Calculation: MAD = Σ(|close-SMA|) / period @@ -10,10 +12,7 @@ Calculation: Sources: https://en.wikipedia.org/wiki/Average_absolute_deviation -**/ - -using System; -namespace QuanTAlib; + */ public class MAD_Series : Single_TSeries_Indicator { diff --git a/Source/Statistics/MAPE_Series.cs b/Source/Statistics/MAPE_Series.cs index 9b5f9d10..a30185cc 100644 --- a/Source/Statistics/MAPE_Series.cs +++ b/Source/Statistics/MAPE_Series.cs @@ -1,7 +1,9 @@ -/** -MAPE: Mean Absolute Percentage Error +namespace QuanTAlib; +using System; -Measures the size of the error in percentage terms +/* +MAPE: Mean Absolute Percentage Error + Measures the size of the error in percentage terms Calculation: MAPE = Σ(|close – SMA| / |close|) / n @@ -9,13 +11,11 @@ Calculation: Sources: https://en.wikipedia.org/wiki/Mean_absolute_percentage_error -Remark: returns infinity if any of observations is 0. -Use SMAPE or WMAPE instead to avoid division-by-zero in MAPE +Remark: + returns infinity if any of observations is 0. + Use SMAPE or WMAPE instead to avoid division-by-zero in MAPE -**/ - -using System; -namespace QuanTAlib; + */ public class MAPE_Series : Single_TSeries_Indicator { diff --git a/Source/Statistics/MED_Series.cs b/Source/Statistics/MED_Series.cs index 60629067..56c9bbcb 100644 --- a/Source/Statistics/MED_Series.cs +++ b/Source/Statistics/MED_Series.cs @@ -1,25 +1,24 @@ -/* +namespace QuanTAlib; +using System; + +/* MED - Median value + Median of numbers is the middlemost value of the given set of numbers. + It separates the higher half and the lower half of a given data sample. + At least half of the observations are smaller than or equal to median + and at least half of the observations are greater than or equal to the median. -Median of numbers is the middlemost value of the given set of numbers. -It separates the higher half and the lower half of a given data sample. -At least half of the observations are smaller than or equal to median -and at least half of the observations are greater than or equal to the median. + If the number of values is odd, the middlemost observation of the sorted + list is the median of the given data. If the number of values is even, + median is the average of (n/2)th and [(n/2) + 1]th values of the sorted list. -If the number of values is odd, the middlemost observation of the sorted -list is the median of the given data. If the number of values is even, -median is the average of (n/2)th and [(n/2) + 1]th values of the sorted list. - -If period = 0 => period is max + If period = 0 => period is max Sources: https://corporatefinanceinstitute.com/resources/knowledge/other/median/ https://en.wikipedia.org/wiki/Median -*/ - -using System; -namespace QuanTAlib; + */ public class MED_Series : Single_TSeries_Indicator { diff --git a/Source/Statistics/MSE_Series.cs b/Source/Statistics/MSE_Series.cs index 4f634758..1b25ff8a 100644 --- a/Source/Statistics/MSE_Series.cs +++ b/Source/Statistics/MSE_Series.cs @@ -1,17 +1,14 @@ -/** -MSE: Mean Square Error +namespace QuanTAlib; +using System; -Defined as a Mean (Average) of the Square of the difference between actual and estimated values. +/* +MSE: Mean Square Error + Defined as a Mean (Average) of the Square of the difference between actual and estimated values. Sources: https://en.wikipedia.org/wiki/Mean_squared_error -Remark: - -**/ - -using System; -namespace QuanTAlib; + */ public class MSE_Series : Single_TSeries_Indicator { diff --git a/Source/Statistics/PSDEV_Series.cs b/Source/Statistics/PSDEV_Series.cs index a5567784..d2a8bba1 100644 --- a/Source/Statistics/PSDEV_Series.cs +++ b/Source/Statistics/PSDEV_Series.cs @@ -1,8 +1,10 @@ -/** -PSDEV: Population Standard Deviation +namespace QuanTAlib; +using System; -Population Standard Deviation is the square root of the biased variance, also knons as -Uncorrected Sample Standard Deviation +/* +PSDEV: Population Standard Deviation + Population Standard Deviation is the square root of the biased variance, also knons as + Uncorrected Sample Standard Deviation Sources: https://en.wikipedia.org/wiki/Standard_deviation#Uncorrected_sample_standard_deviation @@ -11,10 +13,7 @@ Remark: PSDEV (Population Standard Deviation) is also known as a biased/uncorrected Standard Deviation. For unbiased version that uses Bessel's correction, use SDEV instead. -**/ - -using System; -namespace QuanTAlib; + */ public class PSDEV_Series : Single_TSeries_Indicator { diff --git a/Source/Statistics/PVAR_Series.cs b/Source/Statistics/PVAR_Series.cs index 384cc5c4..487aefd2 100644 --- a/Source/Statistics/PVAR_Series.cs +++ b/Source/Statistics/PVAR_Series.cs @@ -1,7 +1,9 @@ -/** -PVAR: Population Variance +namespace QuanTAlib; +using System; -Population variance.... +/* +PVAR: Population Variance + Population variance without Bessel's correction Sources: https://en.wikipedia.org/wiki/Variance @@ -11,10 +13,7 @@ Remark: PVAR (Population Variance) is also known as a biased Sample Variance. For unbiased sample variance use SVAR instead. -**/ - -using System; -namespace QuanTAlib; + */ public class PVAR_Series : Single_TSeries_Indicator { diff --git a/Source/Statistics/SDEV_Series.cs b/Source/Statistics/SDEV_Series.cs index c4fe6d79..73253d53 100644 --- a/Source/Statistics/SDEV_Series.cs +++ b/Source/Statistics/SDEV_Series.cs @@ -1,21 +1,19 @@ -/** -SDEV: (Corrected) Sample Standard Deviation +namespace QuanTAlib; +using System; -Sample Standard Deviaton uses Bessel's correction to correct the bias in the variance. +/* +SDEV: (Corrected) Sample Standard Deviation + Sample Standard Deviaton uses Bessel's correction to correct the bias in the variance. Sources: https://en.wikipedia.org/wiki/Standard_deviation#Corrected_sample_standard_deviation Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction Remark: - SSDEV (Sample Standard Deviation) is also known as a unbiased/corrected Standard Deviation. For a population/biased/uncorrected Standard Deviation, use PSDEV instead -**/ - -using System; -namespace QuanTAlib; + */ public class SDEV_Series : Single_TSeries_Indicator { diff --git a/Source/Statistics/SMAPE_Series.cs b/Source/Statistics/SMAPE_Series.cs index 0674a859..7fe8dd07 100644 --- a/Source/Statistics/SMAPE_Series.cs +++ b/Source/Statistics/SMAPE_Series.cs @@ -1,15 +1,14 @@ -/** -SMAPE: Symmetric Mean Absolute Percentage Error +namespace QuanTAlib; +using System; -Measures the size of the error in percentage terms +/* +SMAPE: Symmetric Mean Absolute Percentage Error + Measures the size of the error in percentage terms Sources: https://en.wikipedia.org/wiki/Symmetric_mean_absolute_percentage_error -**/ - -using System; -namespace QuanTAlib; + */ public class SMAPE_Series : Single_TSeries_Indicator { diff --git a/Source/Statistics/VAR_Series.cs b/Source/Statistics/VAR_Series.cs index 2e2a0150..7d98b1c6 100644 --- a/Source/Statistics/VAR_Series.cs +++ b/Source/Statistics/VAR_Series.cs @@ -1,7 +1,9 @@ -/** -VAR: Sample Variance +namespace QuanTAlib; +using System; -Sample variance uses Bessel's correction to correct the bias in the estimation of population variance. +/* +VAR: Sample Variance + Sample variance uses Bessel's correction to correct the bias in the estimation of population variance. Sources: https://en.wikipedia.org/wiki/Variance @@ -11,10 +13,7 @@ Remark: VAR is also known as the Unbiased Sample Variance, while PVAR (Population Variance) is known as the Biased Sample Variance. -**/ - -using System; -namespace QuanTAlib; + */ public class VAR_Series : Single_TSeries_Indicator { diff --git a/Source/Statistics/WMAPE_Series.cs b/Source/Statistics/WMAPE_Series.cs index 9ed41183..c9780f9c 100644 --- a/Source/Statistics/WMAPE_Series.cs +++ b/Source/Statistics/WMAPE_Series.cs @@ -1,15 +1,14 @@ -/** -WMAPE: Weighted Mean Absolute Percentage Error +namespace QuanTAlib; +using System; -Measures the size of the error in percentage terms +/* +WMAPE: Weighted Mean Absolute Percentage Error + Measures the size of the error in percentage terms Sources: https://en.wikipedia.org/wiki/WMAPE -**/ - -using System; -namespace QuanTAlib; + */ public class WMAPE_Series : Single_TSeries_Indicator { diff --git a/Tests/Validations/Skender_Stock.cs b/Tests/Validations/Skender_Stock.cs index fb59a3ed..dc2de31d 100644 --- a/Tests/Validations/Skender_Stock.cs +++ b/Tests/Validations/Skender_Stock.cs @@ -90,4 +90,22 @@ public class Skender_Stock Assert.Equal(Math.Round((double)SK.Last().Mape!, 8), Math.Round(QL.Last().v, 8)); } + [Fact] + public void ATR() + { + 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)); + } + + + [Fact] + public void ATRP() + { + 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)); + } } diff --git a/Tests/Validations/TA_LIB.cs b/Tests/Validations/TA_LIB.cs index 89246cd7..2d5406b4 100644 --- a/Tests/Validations/TA_LIB.cs +++ b/Tests/Validations/TA_LIB.cs @@ -10,14 +10,22 @@ public class TA_LIB private readonly Random rnd = new(); private readonly int period; private readonly double[] TALIB; - private readonly double[] input; + private readonly double[] inopen; + private readonly double[] inhigh; + private readonly double[] inlow; + private readonly double[] inclose; + private readonly double[] involume; public TA_LIB() { this.bars = new(1000); this.period = this.rnd.Next(28) + 3; this.TALIB = new double[this.bars.Count]; - this.input = this.bars.Close.v.ToArray(); + this.inopen = this.bars.Open.v.ToArray(); + this.inhigh = this.bars.High.v.ToArray(); + this.inlow = this.bars.Low.v.ToArray(); + this.inclose = this.bars.Close.v.ToArray(); + this.involume = this.bars.Volume.v.ToArray(); } ///////////////////////////////////////// @@ -26,7 +34,7 @@ public class TA_LIB public void SMA() { SMA_Series QL = new(this.bars.Close, this.period, false); - Core.Sma(this.input, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + 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)); } @@ -35,7 +43,7 @@ public class TA_LIB public void EMA() { EMA_Series QL = new(this.bars.Close, this.period, false); - Core.Ema(this.input, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + 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)); } @@ -44,7 +52,7 @@ public class TA_LIB public void WMA() { WMA_Series QL = new(this.bars.Close, this.period, false); - Core.Wma(this.input, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + 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)); } @@ -53,7 +61,7 @@ public class TA_LIB public void DEMA() { DEMA_Series QL = new(this.bars.Close, this.period, false); - Core.Dema(this.input, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + 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)); } @@ -62,7 +70,7 @@ public class TA_LIB public void TEMA() { TEMA_Series QL = new(this.bars.Close, this.period, false); - Core.Tema(this.input, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + 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)); } @@ -71,7 +79,7 @@ public class TA_LIB public void MAX() { MAX_Series QL = new(this.bars.Close, this.period, false); - Core.Max(this.input, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + 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)); } @@ -80,9 +88,17 @@ public class TA_LIB public void MIN() { MIN_Series QL = new(this.bars.Close, this.period, false); - Core.Min(this.input, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); + 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)); } + [Fact] + public void ATR() + { + 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)); + } }