From c80f57ddabafe269a7e8c704082076679dcb936f Mon Sep 17 00:00:00 2001 From: Miha Kralj Date: Mon, 17 Apr 2023 16:54:23 -0700 Subject: [PATCH 1/4] Update 2MASlope_chart.cs --- Indicators/Charts/2MASlope_chart.cs | 22 +++++++++++++++------- Indicators/Charts/TrailingStop.cs | 1 - 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Indicators/Charts/2MASlope_chart.cs b/Indicators/Charts/2MASlope_chart.cs index 2c52110e..4f65c53e 100644 --- a/Indicators/Charts/2MASlope_chart.cs +++ b/Indicators/Charts/2MASlope_chart.cs @@ -50,6 +50,8 @@ public class MovingAverageSlope_chart : Indicator { private TSeries MA1, MA2; private LINREG_Series sMA1, sMA2; private CROSS_Series sig1, sig2; + + private bool inLong, inShort; /////// public MovingAverageSlope_chart() { @@ -240,31 +242,37 @@ public class MovingAverageSlope_chart : Indicator { this.LinesSeries[1].SetMarker(0,s2Color); if (sig1[^1].v > 0 || sig2[^1].v > 0) { - if (sMA1[^1].v >= 0 && sMA2[^1].v >= 0) + if (sMA1[^1].v >= 0 && sMA2[^1].v >= 0 && LongTrades) { + inLong = true; this.BeginCloud(0, 1, Color.FromArgb(127, Color.DarkGreen)); this.LinesSeries[(this.MA1[^1].v < this.MA2[^1].v)? 0 : 1 ].SetMarker(0, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.UpArrow)); } else { this.EndCloud(0, 1, Color.Empty); - this.LinesSeries[(this.MA1[^1].v < this.MA2[^1].v) ? 1 : 0].SetMarker(1, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.DownArrow)); + if (inShort) + { + this.LinesSeries[(this.MA1[^1].v < this.MA2[^1].v) ? 1 : 0].SetMarker(1, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.DownArrow)); + inShort = false; + } } - } if (sig1[^1].v < 0 || sig2[^1].v < 0) { - if (sMA1[^1].v <= 0 && sMA2[^1].v <= 0) + if (sMA1[^1].v <= 0 && sMA2[^1].v <= 0 && ShortTrades) { + inShort = true; this.BeginCloud(0, 1, Color.FromArgb(100, Color.Red)); this.LinesSeries[(this.MA1[^1].v > this.MA2[^1].v) ? 0 : 1].SetMarker(0, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.UpArrow)); - } else { this.EndCloud(0, 1, Color.Empty); - this.LinesSeries[(this.MA1[^1].v > this.MA2[^1].v)?1:0].SetMarker(1, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.DownArrow)); + if (inLong) { + LinesSeries[(this.MA1[^1].v > this.MA2[^1].v)?1:0].SetMarker(1, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.DownArrow)); + inLong = false; + } } } - } public override void OnPaintChart(PaintChartEventArgs args) { base.OnPaintChart(args); diff --git a/Indicators/Charts/TrailingStop.cs b/Indicators/Charts/TrailingStop.cs index 3413ccb5..2f20542e 100644 --- a/Indicators/Charts/TrailingStop.cs +++ b/Indicators/Charts/TrailingStop.cs @@ -90,7 +90,6 @@ public class TrailingStop_chart : Indicator { this.SetValue(_ratchetL, lineIndex: 1); this.SetValue(_tslineS, lineIndex: 2); this.SetValue(_ratchetS, lineIndex: 3); - } public override void OnPaintChart(PaintChartEventArgs args) { From abdcbf5f2088cab1ddc1087edbdb1c6ce12dd5e4 Mon Sep 17 00:00:00 2001 From: Miha Kralj Date: Mon, 24 Apr 2023 11:39:41 -0700 Subject: [PATCH 2/4] Update RSI_Series to check for period != 0 before calculating RSI --- Calculations/Basics/MAX_Series.cs | 25 - Calculations/Basics/MIDPOINT_Series.cs | 37 -- Calculations/Basics/MIN_Series.cs | 25 - Calculations/Basics/SUM_Series.cs | 35 -- Calculations/Basics/ZL_Series.cs | 34 -- Calculations/Calculations.csproj | 148 ++--- .../ClassStructures/Single_TBars_Abstract.cs | 2 +- .../Single_TSeries_Abstract.cs | 43 +- Calculations/ClassStructures/TBars.cs | 136 ----- Calculations/ClassStructures/TSeries.cs | 63 -- Calculations/Logic/EQUITY_Series.cs | 2 +- Calculations/Statistics/BIAS_Series.cs | 34 -- Calculations/Statistics/DECAY_Series.cs | 39 -- Calculations/Statistics/ENTROPY_Series.cs | 44 -- Calculations/Statistics/KURTOSIS_Series.cs | 57 -- Calculations/Statistics/MAD_Series.cs | 38 -- Calculations/Statistics/MAPE_Series.cs | 42 -- Calculations/Statistics/MEDIAN_Series.cs | 44 -- Calculations/Statistics/MSE_Series.cs | 33 -- Calculations/Statistics/SDEV_Series.cs | 39 -- Calculations/Statistics/SMAPE_Series.cs | 33 -- Calculations/Statistics/SSDEV_Series.cs | 39 -- Calculations/Statistics/SVAR_Series.cs | 38 -- Calculations/Statistics/VAR_Series.cs | 38 -- Calculations/Statistics/WMAPE_Series.cs | 40 -- Calculations/Statistics/ZSCORE_Series.cs | 46 -- Calculations/Trends/ALMA_Series.cs | 63 -- .../{Momentum => Trends}/CCI_Series.cs | 0 Calculations/Trends/DEMA_Series.cs | 72 --- Calculations/Trends/DWMA_Series.cs | 33 -- Calculations/Trends/EMA_Series.cs | 71 --- Calculations/Trends/FMA_Series.cs | 59 -- Calculations/Trends/HEMA_Series.cs | 57 -- Calculations/Trends/HMA_Series.cs | 119 ---- Calculations/Trends/KAMA_Series.cs | 64 -- Calculations/Trends/MAMA_Series.cs | 205 ++++--- Calculations/Trends/RMA_Series.cs | 56 -- Calculations/Trends/SMA_Series.cs | 44 -- Calculations/Trends/SMMA_Series.cs | 51 -- Calculations/Trends/T3_Series.cs | 100 ---- Calculations/Trends/TEMA_Series.cs | 70 --- Calculations/Trends/TRIMA_Series.cs | 43 -- Calculations/Trends/TRIX_Series.cs | 75 --- Calculations/Trends/WMA_Series.cs | 35 -- Calculations/Trends/ZLEMA_Series.cs | 62 -- Calculations/Volatility/ATRP_Series.cs | 2 +- Calculations/Volatility/CMO_Series.cs | 46 -- .../{Volume => Volatility}/OBV_Series.cs | 0 Calculations/Volatility/RSI_Series.cs | 78 --- Calculations/_Updated/ALMA_Series.cs | 107 ++++ Calculations/_Updated/BIAS_Series.cs | 75 +++ Calculations/_Updated/CMO_Series.cs | 92 +++ Calculations/_Updated/CUSUM_Series.cs | 74 +++ Calculations/_Updated/DECAY_Series.cs | 86 +++ Calculations/_Updated/DEMA_Series.cs | 131 +++++ Calculations/_Updated/DWMA_Series.cs | 126 ++++ Calculations/_Updated/EMA_Series.cs | 123 ++++ Calculations/_Updated/ENTROPY_Series.cs | 90 +++ Calculations/_Updated/FWMA_Series.cs | 100 ++++ Calculations/_Updated/HEMA_Series.cs | 116 ++++ Calculations/_Updated/HMA_Series.cs | 91 +++ .../{Trends => _Updated}/JMA_Series.cs | 86 ++- Calculations/_Updated/KAMA_Series.cs | 114 ++++ Calculations/_Updated/KURTOSIS_Series.cs | 99 ++++ Calculations/_Updated/MAD_Series.cs | 82 +++ Calculations/_Updated/MAPE_Series.cs | 88 +++ Calculations/_Updated/MAX_Series.cs | 71 +++ Calculations/_Updated/MEDIAN_Series.cs | 89 +++ Calculations/_Updated/MIDPOINT_Series.cs | 75 +++ Calculations/_Updated/MIN_Series.cs | 71 +++ Calculations/_Updated/MSE_Series.cs | 79 +++ Calculations/_Updated/RMA_Series.cs | 119 ++++ Calculations/_Updated/RSI_Series.cs | 123 ++++ Calculations/_Updated/SDEV_Series.cs | 85 +++ Calculations/_Updated/SMAPE_Series.cs | 80 +++ Calculations/_Updated/SMA_Series.cs | 99 ++++ Calculations/_Updated/SMMA_Series.cs | 96 +++ Calculations/_Updated/SSDEV_Series.cs | 85 +++ Calculations/_Updated/SVAR_Series.cs | 84 +++ Calculations/_Updated/T3_Series.cs | 164 ++++++ Calculations/_Updated/TBars.cs | 126 ++++ Calculations/_Updated/TEMA_Series.cs | 123 ++++ Calculations/_Updated/TRIMA_Series.cs | 87 +++ Calculations/_Updated/TRIX_Series.cs | 119 ++++ Calculations/_Updated/TSeries.cs | 85 +++ Calculations/_Updated/VAR_Series.cs | 84 +++ Calculations/_Updated/WMAPE_Series.cs | 85 +++ Calculations/_Updated/WMA_Series.cs | 107 ++++ Calculations/_Updated/ZLEMA_Series.cs | 97 ++++ Calculations/_Updated/ZL_Series.cs | 93 +++ Calculations/_Updated/ZSCORE_Series.cs | 91 +++ Calculations/_Updated/zMA_Series.cs | 72 +++ Indicators/Charts/2MACross_chart.cs | 12 +- Indicators/Charts/2MASlope_chart.cs | 18 +- Indicators/Charts/JMA_chart.cs | 4 +- Indicators/Indicators.csproj | 2 + Strategies/SimpleMACross1.cs | 2 +- Strategies/Strategies.csproj | 2 + Tests/Basic tests/Indicators.cs | 153 +++++ Tests/Basic tests/Oscillators.cs | 158 +++++ Tests/Basics/Abstract_Test.cs | 23 - Tests/Basics/TSeries_Test.cs | 61 -- Tests/MovingAvg/ALMA_Test.cs | 32 - Tests/MovingAvg/BBANDS_Test.cs | 56 -- Tests/MovingAvg/DEMA_Test.cs | 31 - Tests/MovingAvg/DWMA_Test.cs | 32 - Tests/MovingAvg/EMA_Test.cs | 32 - Tests/MovingAvg/FMA_Test.cs | 31 - Tests/MovingAvg/HEMA_Test.cs | 31 - Tests/MovingAvg/HMA_Test.cs | 31 - Tests/MovingAvg/JMA_Test.cs | 31 - Tests/MovingAvg/KAMA_Test.cs | 31 - Tests/MovingAvg/MACD_Test.cs | 31 - Tests/MovingAvg/RMA_Test.cs | 31 - Tests/MovingAvg/RSI_Test.cs | 31 - Tests/MovingAvg/SMA_Test.cs | 31 - Tests/MovingAvg/SMMA_Test.cs | 31 - Tests/MovingAvg/TEMA_Test.cs | 31 - Tests/MovingAvg/WMA_Test.cs | 31 - Tests/MovingAvg/ZLEMA_Test.cs | 31 - Tests/{Basics => Pairs}/ADD_Test.cs | 2 +- Tests/{Basics => Pairs}/DIV_Test.cs | 2 +- Tests/{Basics => Pairs}/MUL_Test.cs | 2 +- Tests/{Basics => Pairs}/SUB_Test.cs | 2 +- Tests/{Basics => Pairs}/TBars_Test.cs | 224 +++---- Tests/Series/Update.cs | 545 ------------------ Tests/Statistics/BIAS_Test.cs | 31 - Tests/Statistics/ENTP_Test.cs | 31 - Tests/Statistics/KURT_Test.cs | 31 - Tests/Statistics/LINREG_Test.cs | 31 - Tests/Statistics/MAD_Test.cs | 31 - Tests/Statistics/MAPE_Test.cs | 31 - Tests/Statistics/MAX_Test.cs | 31 - Tests/Statistics/MED_Test.cs | 31 - Tests/Statistics/MIN_Test.cs | 31 - Tests/Statistics/MSE_Test.cs | 31 - Tests/Statistics/PSDEV_Test.cs | 31 - Tests/Statistics/PVAR_Test .cs | 31 - Tests/Statistics/SDEV_Test .cs | 31 - Tests/Statistics/SMAPE_Test.cs | 31 - Tests/Statistics/VAR_Test.cs | 31 - Tests/Statistics/WMAPE_Test.cs | 31 - Tests/Tests.csproj | 7 +- Tests/Validations/Trends/TA_LIB.cs | 2 +- Tests/Validations/Trends/Tulip.cs | 2 +- 145 files changed, 4826 insertions(+), 4207 deletions(-) delete mode 100644 Calculations/Basics/MAX_Series.cs delete mode 100644 Calculations/Basics/MIDPOINT_Series.cs delete mode 100644 Calculations/Basics/MIN_Series.cs delete mode 100644 Calculations/Basics/SUM_Series.cs delete mode 100644 Calculations/Basics/ZL_Series.cs delete mode 100644 Calculations/ClassStructures/TBars.cs delete mode 100644 Calculations/ClassStructures/TSeries.cs delete mode 100644 Calculations/Statistics/BIAS_Series.cs delete mode 100644 Calculations/Statistics/DECAY_Series.cs delete mode 100644 Calculations/Statistics/ENTROPY_Series.cs delete mode 100644 Calculations/Statistics/KURTOSIS_Series.cs delete mode 100644 Calculations/Statistics/MAD_Series.cs delete mode 100644 Calculations/Statistics/MAPE_Series.cs delete mode 100644 Calculations/Statistics/MEDIAN_Series.cs delete mode 100644 Calculations/Statistics/MSE_Series.cs delete mode 100644 Calculations/Statistics/SDEV_Series.cs delete mode 100644 Calculations/Statistics/SMAPE_Series.cs delete mode 100644 Calculations/Statistics/SSDEV_Series.cs delete mode 100644 Calculations/Statistics/SVAR_Series.cs delete mode 100644 Calculations/Statistics/VAR_Series.cs delete mode 100644 Calculations/Statistics/WMAPE_Series.cs delete mode 100644 Calculations/Statistics/ZSCORE_Series.cs delete mode 100644 Calculations/Trends/ALMA_Series.cs rename Calculations/{Momentum => Trends}/CCI_Series.cs (100%) delete mode 100644 Calculations/Trends/DEMA_Series.cs delete mode 100644 Calculations/Trends/DWMA_Series.cs delete mode 100644 Calculations/Trends/EMA_Series.cs delete mode 100644 Calculations/Trends/FMA_Series.cs delete mode 100644 Calculations/Trends/HEMA_Series.cs delete mode 100644 Calculations/Trends/HMA_Series.cs delete mode 100644 Calculations/Trends/KAMA_Series.cs delete mode 100644 Calculations/Trends/RMA_Series.cs delete mode 100644 Calculations/Trends/SMA_Series.cs delete mode 100644 Calculations/Trends/SMMA_Series.cs delete mode 100644 Calculations/Trends/T3_Series.cs delete mode 100644 Calculations/Trends/TEMA_Series.cs delete mode 100644 Calculations/Trends/TRIMA_Series.cs delete mode 100644 Calculations/Trends/TRIX_Series.cs delete mode 100644 Calculations/Trends/WMA_Series.cs delete mode 100644 Calculations/Trends/ZLEMA_Series.cs delete mode 100644 Calculations/Volatility/CMO_Series.cs rename Calculations/{Volume => Volatility}/OBV_Series.cs (100%) delete mode 100644 Calculations/Volatility/RSI_Series.cs create mode 100644 Calculations/_Updated/ALMA_Series.cs create mode 100644 Calculations/_Updated/BIAS_Series.cs create mode 100644 Calculations/_Updated/CMO_Series.cs create mode 100644 Calculations/_Updated/CUSUM_Series.cs create mode 100644 Calculations/_Updated/DECAY_Series.cs create mode 100644 Calculations/_Updated/DEMA_Series.cs create mode 100644 Calculations/_Updated/DWMA_Series.cs create mode 100644 Calculations/_Updated/EMA_Series.cs create mode 100644 Calculations/_Updated/ENTROPY_Series.cs create mode 100644 Calculations/_Updated/FWMA_Series.cs create mode 100644 Calculations/_Updated/HEMA_Series.cs create mode 100644 Calculations/_Updated/HMA_Series.cs rename Calculations/{Trends => _Updated}/JMA_Series.cs (54%) create mode 100644 Calculations/_Updated/KAMA_Series.cs create mode 100644 Calculations/_Updated/KURTOSIS_Series.cs create mode 100644 Calculations/_Updated/MAD_Series.cs create mode 100644 Calculations/_Updated/MAPE_Series.cs create mode 100644 Calculations/_Updated/MAX_Series.cs create mode 100644 Calculations/_Updated/MEDIAN_Series.cs create mode 100644 Calculations/_Updated/MIDPOINT_Series.cs create mode 100644 Calculations/_Updated/MIN_Series.cs create mode 100644 Calculations/_Updated/MSE_Series.cs create mode 100644 Calculations/_Updated/RMA_Series.cs create mode 100644 Calculations/_Updated/RSI_Series.cs create mode 100644 Calculations/_Updated/SDEV_Series.cs create mode 100644 Calculations/_Updated/SMAPE_Series.cs create mode 100644 Calculations/_Updated/SMA_Series.cs create mode 100644 Calculations/_Updated/SMMA_Series.cs create mode 100644 Calculations/_Updated/SSDEV_Series.cs create mode 100644 Calculations/_Updated/SVAR_Series.cs create mode 100644 Calculations/_Updated/T3_Series.cs create mode 100644 Calculations/_Updated/TBars.cs create mode 100644 Calculations/_Updated/TEMA_Series.cs create mode 100644 Calculations/_Updated/TRIMA_Series.cs create mode 100644 Calculations/_Updated/TRIX_Series.cs create mode 100644 Calculations/_Updated/TSeries.cs create mode 100644 Calculations/_Updated/VAR_Series.cs create mode 100644 Calculations/_Updated/WMAPE_Series.cs create mode 100644 Calculations/_Updated/WMA_Series.cs create mode 100644 Calculations/_Updated/ZLEMA_Series.cs create mode 100644 Calculations/_Updated/ZL_Series.cs create mode 100644 Calculations/_Updated/ZSCORE_Series.cs create mode 100644 Calculations/_Updated/zMA_Series.cs create mode 100644 Tests/Basic tests/Indicators.cs create mode 100644 Tests/Basic tests/Oscillators.cs delete mode 100644 Tests/Basics/Abstract_Test.cs delete mode 100644 Tests/Basics/TSeries_Test.cs delete mode 100644 Tests/MovingAvg/ALMA_Test.cs delete mode 100644 Tests/MovingAvg/BBANDS_Test.cs delete mode 100644 Tests/MovingAvg/DEMA_Test.cs delete mode 100644 Tests/MovingAvg/DWMA_Test.cs delete mode 100644 Tests/MovingAvg/EMA_Test.cs delete mode 100644 Tests/MovingAvg/FMA_Test.cs delete mode 100644 Tests/MovingAvg/HEMA_Test.cs delete mode 100644 Tests/MovingAvg/HMA_Test.cs delete mode 100644 Tests/MovingAvg/JMA_Test.cs delete mode 100644 Tests/MovingAvg/KAMA_Test.cs delete mode 100644 Tests/MovingAvg/MACD_Test.cs delete mode 100644 Tests/MovingAvg/RMA_Test.cs delete mode 100644 Tests/MovingAvg/RSI_Test.cs delete mode 100644 Tests/MovingAvg/SMA_Test.cs delete mode 100644 Tests/MovingAvg/SMMA_Test.cs delete mode 100644 Tests/MovingAvg/TEMA_Test.cs delete mode 100644 Tests/MovingAvg/WMA_Test.cs delete mode 100644 Tests/MovingAvg/ZLEMA_Test.cs rename Tests/{Basics => Pairs}/ADD_Test.cs (98%) rename Tests/{Basics => Pairs}/DIV_Test.cs (98%) rename Tests/{Basics => Pairs}/MUL_Test.cs (98%) rename Tests/{Basics => Pairs}/SUB_Test.cs (98%) rename Tests/{Basics => Pairs}/TBars_Test.cs (95%) delete mode 100644 Tests/Series/Update.cs delete mode 100644 Tests/Statistics/BIAS_Test.cs delete mode 100644 Tests/Statistics/ENTP_Test.cs delete mode 100644 Tests/Statistics/KURT_Test.cs delete mode 100644 Tests/Statistics/LINREG_Test.cs delete mode 100644 Tests/Statistics/MAD_Test.cs delete mode 100644 Tests/Statistics/MAPE_Test.cs delete mode 100644 Tests/Statistics/MAX_Test.cs delete mode 100644 Tests/Statistics/MED_Test.cs delete mode 100644 Tests/Statistics/MIN_Test.cs delete mode 100644 Tests/Statistics/MSE_Test.cs delete mode 100644 Tests/Statistics/PSDEV_Test.cs delete mode 100644 Tests/Statistics/PVAR_Test .cs delete mode 100644 Tests/Statistics/SDEV_Test .cs delete mode 100644 Tests/Statistics/SMAPE_Test.cs delete mode 100644 Tests/Statistics/VAR_Test.cs delete mode 100644 Tests/Statistics/WMAPE_Test.cs diff --git a/Calculations/Basics/MAX_Series.cs b/Calculations/Basics/MAX_Series.cs deleted file mode 100644 index 109461a9..00000000 --- a/Calculations/Basics/MAX_Series.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 System.Collections.Generic.List _buffer = new(); - - public override void Add((DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _max = _buffer.Max(); - - base.Add((TValue.t, _max), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Basics/MIDPOINT_Series.cs b/Calculations/Basics/MIDPOINT_Series.cs deleted file mode 100644 index d96a39a6..00000000 --- a/Calculations/Basics/MIDPOINT_Series.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -MIDPOINT: Midpoint value (max+min)/2 in the given period in the series. - If period = 0 => period = full length of the series - -Sources: - https://thefaqblog.com/what-is-the-midpoint-in-statistics/ - - */ - -public class MIDPOINT_Series : Single_TSeries_Indicator -{ - public MIDPOINT_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) - { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - double _max = TValue.v; - double _min = TValue.v; - for (int i = 0; i < this._buffer.Count; i++) - { - _max = Math.Max(this._buffer[i], _max); - _min = Math.Min(this._buffer[i], _min); - } - double _mid = (_max + _min) * 0.5; - - base.Add((TValue.t, _mid), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Basics/MIN_Series.cs b/Calculations/Basics/MIN_Series.cs deleted file mode 100644 index e41a0ba4..00000000 --- a/Calculations/Basics/MIN_Series.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 -{ - public MIN_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - double _min = _buffer.Min(); - base.Add((TValue.t, _min), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Basics/SUM_Series.cs b/Calculations/Basics/SUM_Series.cs deleted file mode 100644 index bb98134d..00000000 --- a/Calculations/Basics/SUM_Series.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -SUM: Cumulative Sum (aka Running Total) - SUM across a period provides a rolling sum of all values across the period. - If SUM values would be divided with period, the output would be SMA() - -Sources: - https://en.wikipedia.org/wiki/CUSUM - - */ - -public class SUM_Series : Single_TSeries_Indicator -{ - public SUM_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - if (update) { _buffer[_buffer.Count - 1] = TValue.v; } - else { _buffer.Add(TValue.v); } - if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); } - - double _sum = 0; - for (int i = 0; i < _buffer.Count; i++) { _sum += _buffer[i]; } - - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _sum); - - base.Add(result, update); - } -} diff --git a/Calculations/Basics/ZL_Series.cs b/Calculations/Basics/ZL_Series.cs deleted file mode 100644 index 0a85f65b..00000000 --- a/Calculations/Basics/ZL_Series.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -ZL: Zero Lag - Data is de-lagged by removing the data from “lag” days ago, thus removing - (or attempting to) the cumulative effect of the moving average. - -Calculation: - Lag = (Period-1)/2 - ZL = Data + (Data - Data(Lag days ago) ) - -Sources: - https://mudrex.com/blog/zero-lag-ema-trading-strategy/ - - */ - -public class ZL_Series : Single_TSeries_Indicator -{ - public ZL_Series(TSeries source, int period, bool useNaN = false) : base(source, period:period, useNaN:useNaN) { - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((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); - - 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/Calculations/Calculations.csproj b/Calculations/Calculations.csproj index 4140e36e..466a0ced 100644 --- a/Calculations/Calculations.csproj +++ b/Calculations/Calculations.csproj @@ -1,74 +1,82 @@ - - - QuanTAlib - 0.2.0 - Library of TA Calculations, Charts and Strategies for Quantower - Quantitative Technical Analysis Library in C# for Quantower - git - https://github.com/mihakralj/QuanTAlib - true - Miha Kralj - Miha Kralj - readme.md - net8.0;net7.0;net6.0 - disable - preview - disable - true - en-US - QuanTAlib - QuanTAlib - True - AnyCPU - False - embedded - True - True - + + + + QuanTAlib + 0.2.0 + Library of TA Calculations, Charts and Strategies for Quantower + Quantitative Technical Analysis Library in C# for Quantower + git + https://github.com/mihakralj/QuanTAlib + true + Miha Kralj + Miha Kralj + readme.md + net8.0;net7.0;net6.0 + disable + preview + disable + true + en-US + QuanTAlib + QuanTAlib + True + AnyCPU + False + embedded + True + True + Indicators;Stock;Market;Technical;Analysis;Algorithmic;Trading;Trade;Trend;Momentum;Finance;Algorithm;Algo; AlgoTrading;Financial;Strategy;Chart;Charting;Oscillator;Overlay;Equity;Bitcoin;Crypto;Cryptocurrency;Forex; Quantitative;Historical;Quotes; - - Apache-2.0 - - 0.2.1.0 - 0.2.1.0 - 0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d - NETSDK1057 - - - full - True - 7 - True - anycpu - - - - True - 7 - True - anycpu - - - QuanTAlib2.png - https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png - True - ..\.sonarlint\mihakralj_quantalibcsharp.ruleset - 0.2.1-dev.2 - - - - - - - True - - - - True - False - - - + + Apache-2.0 + + + 0.2.1.0 + 0.2.1.0 + 0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d + NETSDK1057 + IDE1006 + true + $(NoWarn);NETSDK1057 + + + full + True + 7 + True + anycpu + + + + + True + 7 + True + anycpu + + + QuanTAlib2.png + https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png + True + ..\.sonarlint\mihakralj_quantalibcsharp.ruleset + 0.2.1-dev.2 + + + + + + + True + + + + + True + False + + + + \ No newline at end of file diff --git a/Calculations/ClassStructures/Single_TBars_Abstract.cs b/Calculations/ClassStructures/Single_TBars_Abstract.cs index 4d5e3170..1d3c8ac8 100644 --- a/Calculations/ClassStructures/Single_TBars_Abstract.cs +++ b/Calculations/ClassStructures/Single_TBars_Abstract.cs @@ -44,7 +44,7 @@ public abstract class Single_TBars_Indicator : TSeries // 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 virtual new 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); diff --git a/Calculations/ClassStructures/Single_TSeries_Abstract.cs b/Calculations/ClassStructures/Single_TSeries_Abstract.cs index d52ad80d..ca8d3d89 100644 --- a/Calculations/ClassStructures/Single_TSeries_Abstract.cs +++ b/Calculations/ClassStructures/Single_TSeries_Abstract.cs @@ -23,29 +23,32 @@ public abstract class Single_TSeries_Indicator : TSeries protected readonly TSeries _data; protected int _p; - // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN) - protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN) { - _data = source; - _period = period; - _p = _period; - _NaN = useNaN; - _data.Pub += Sub; - } + // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN) + protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN) + { + _data = source; + _period = period; + _p = _period; + _NaN = useNaN; + _data.Pub += Sub; + } - // overridable Add() method to add/update a single item at the end of the list + // overridable Add() method to add/update a single item at the end of the list - public virtual void Add((DateTime t, double v) TValue, bool update, bool useNaN) { - if (_period == 0) { _p = Length; } - var res = (TValue.t, Count < _p - 1 && _NaN ? double.NaN : TValue.v); - base.Add(res, update); - } - public new virtual void Add((DateTime t, double v) TValue, bool update) => base.Add(TValue, update); + public virtual void Add((DateTime t, double v) TValue, bool update, bool useNaN) + { + if (_period == 0) { _p = Length; } + var res = (TValue.t, Count < _p - 1 && _NaN ? double.NaN : TValue.v); + base.Add(res, update); + } + public new virtual void Add((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) { - foreach (var item in data) { Add(TValue: item, update: false); } - } - public new void Add((System.DateTime t, double v) TValue) => this.Add(TValue: TValue, update: false); + // potentially overridable Add() method for the whole series (could be replaced with faster bulk algo) + public virtual new void Add(TSeries data) + { + foreach (var item in data) { Add(TValue: item, 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); diff --git a/Calculations/ClassStructures/TBars.cs b/Calculations/ClassStructures/TBars.cs deleted file mode 100644 index 562cc968..00000000 --- a/Calculations/ClassStructures/TBars.cs +++ /dev/null @@ -1,136 +0,0 @@ -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(); - private readonly TSeries _high = new(); - private readonly TSeries _low = new(); - private readonly TSeries _close = new(); - private readonly TSeries _volume = new(); - private readonly TSeries _hl2 = new(); - private readonly TSeries _oc2 = new(); - private readonly TSeries _ohl3 = new(); - private readonly TSeries _hlc3 = new(); - private readonly TSeries _ohlc4 = new(); - private readonly TSeries _hlcc4 = new(); - - public TSeries Open => this._open; - public TSeries High => this._high; - public TSeries Low => this._low; - public TSeries Close => this._close; - public TSeries Volume => this._volume; - public TSeries HL2 => this._hl2; - public TSeries OC2 => this._oc2; - public TSeries OHL3 => this._ohl3; - public TSeries HLC3 => this._hlc3; - public TSeries OHLC4 => this._ohlc4; - public TSeries HLCC4 => this._hlcc4; - - public TBars Tail(int count = 10) - { - TBars outBars = new(); - if (count > this.Count) { count = this.Count; } - for (int i = this.Count - count; i < this.Count; i++) { outBars.Add(this[i]); } - return outBars; - } - public TSeries Select(int source) - { - return source switch - { - 0 => _open, - 1 => _high, - 2 => _low, - 3 => _close, - 4 => _hl2, - 5 => _oc2, - 6 => _ohl3, - 7 => _hlc3, - 8 => _ohlc4, - _ => _hlcc4, - }; - } - public static string SelectStr(int source) - { - return source switch - { - 0 => "Open", - 1 => "High", - 2 => "Low", - 3 => "Close", - 4 => "HL2", - 5 => "OC2", - 6 => "OHL3", - 7 => "HLC3", - 8 => "OHLC4", - _ => "HLCC4", - }; - } - - public 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); - - public void Add(DateTime t, decimal o, decimal h, decimal l, decimal c, decimal v, bool update = false) - => Add(t, (double)o, (double)h, (double)l, (double)c, (double)v, update); - - public void Add(DateTime t, double o, double h, double l, double c, double v, bool update = false) - { - if (update) { - this[this.Count - 1] = (t, o, h, l, c, v); - } - else { - base.Add((t, o, h, l, c, v)); - } - _open.Add((t, o),update); - _high.Add((t, h), update); - _low.Add((t, l), update); - _close.Add((t, c), update); - _volume.Add((t, v), update); - _hl2.Add((t, (h + l) * 0.5), update); - _oc2.Add((t, (o + c) * 0.5), update); - _ohl3.Add((t, (o + h + l) * 0.333333333333333), update); - _hlc3.Add((t, (h + l + c) * 0.333333333333333), update); - _ohlc4.Add((t, (o + h + l + c) * 0.25), update); - _hlcc4.Add((t, (h + l + c + c) * 0.25), update); - - this.OnEvent(update); - } - - // delegate used by event handler + event handler (Pub == publisher) - public delegate void NewDataEventHandler(object source, TSeriesEventArgs args); - public event NewDataEventHandler Pub; - - // Broadcast handler - only to valid targets - protected virtual void OnEvent(bool update = false) - { - if (Pub != null && Pub.Target != this) - { - Pub(this, new TSeriesEventArgs { update = update }); - } - } - - public void Sub(object source, TSeriesEventArgs e) - { - TBars ss = (TBars)source; - if (ss.Count > 1) - { - for (int i = 0; i < ss.Count; i++) - { - this.Add(ss[i]); - } - } - else - { - this.Add(ss[ss.Count - 1], e.update); - } - } -} diff --git a/Calculations/ClassStructures/TSeries.cs b/Calculations/ClassStructures/TSeries.cs deleted file mode 100644 index eafec24d..00000000 --- a/Calculations/ClassStructures/TSeries.cs +++ /dev/null @@ -1,63 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Data; -using System.Linq; - -/* -TSeries is the cornerstone of all QuanTAlib classes. - TSeries is a single List of tuples (time, value) and contains several operators, casts, overloads - and other helpers that simplify usage of library. - Think of TSeries as an equivalent of Numpy array. - - - includes Length property (to mimic array's method) - - includes publishing and subscribing methods that attach to events - - */ - - -public class TSeriesEventArgs : EventArgs{ - public bool update { get; set; } -} - -public class TSeries : List<(DateTime t, double v)> { - - public static implicit operator (DateTime t, double v)(TSeries l) => l[^1]; - public static implicit operator double(TSeries l) => l[^1].v; - public static implicit operator DateTime(TSeries l) => l[^1].t; - public List t => this.Select(item => item.t).ToList(); - public List v => this.Select(item => item.v).ToList(); - public int Length => this.Count; - - public TSeries Tail(int count = 10) { - var tailSeries = new TSeries(); - tailSeries.AddRange(this.Skip(Math.Max(0, this.Count - count)).Take(count)); - return tailSeries; - } - public (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { - if (update) { this[^1] = TValue; } - else { base.Add(TValue); } - OnEvent(update); - return TValue; - } - - public void Add(DateTime t, double v, bool update = false) => this.Add((t, v), update); - public void Add(double v, bool update = false) => this.Add((DateTime.Now, v), update); - protected virtual void OnEvent(bool update = false) { - Pub?.Invoke(this, new TSeriesEventArgs { update = update }); - } - - public delegate void NewDataEventHandler(object source, TSeriesEventArgs args); - public event NewDataEventHandler Pub; - - public void Sub(object source, TSeriesEventArgs e) { - TSeries ss = (TSeries)source; - if (ss.Count > 0) { - this.AddRange(ss); - } - else { - this.Add(ss[^1], e.update); - } - } -} diff --git a/Calculations/Logic/EQUITY_Series.cs b/Calculations/Logic/EQUITY_Series.cs index 1257352d..50313152 100644 --- a/Calculations/Logic/EQUITY_Series.cs +++ b/Calculations/Logic/EQUITY_Series.cs @@ -81,7 +81,7 @@ public class EQUITY_Series : Single_TSeries_Indicator { //Console.WriteLine($"{TValue.v,3}\t {(_inmarket)} : {_cash,10:f2} + {_units*_price[this.Count-1].v,7:f2} = {_equity-_capital:f2}"); } - inmarket.Add(TValue.t, (double)_inmarket); + inmarket.Add((TValue.t, (double)_inmarket)); base.Add((TValue.t, _equity), update, _NaN); } } \ No newline at end of file diff --git a/Calculations/Statistics/BIAS_Series.cs b/Calculations/Statistics/BIAS_Series.cs deleted file mode 100644 index 7440a5f3..00000000 --- a/Calculations/Statistics/BIAS_Series.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 - = (close / SMA) - 1 - -Sources: - https://en.wikipedia.org/wiki/Bias_of_an_estimator - - */ - -public class BIAS_Series : Single_TSeries_Indicator -{ - public BIAS_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - double _sma = _buffer.Average(); - double _bias = (_buffer[_buffer.Count - 1] / ((_sma != 0) ? _sma : 1)) - 1; - - base.Add((TValue.t, _bias), update, _NaN); - } -} diff --git a/Calculations/Statistics/DECAY_Series.cs b/Calculations/Statistics/DECAY_Series.cs deleted file mode 100644 index 2084c95a..00000000 --- a/Calculations/Statistics/DECAY_Series.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Collections.Generic; - - -/* -DECAY: - Linear decay can be modeled by a straight line with a negative slope of 1/period. - The value decreases in a straight line from the last maximum to 0. - Decay = Last Max - distance/period - - Exponential decay is modeled as an exponential curve with diminishing factor of - 1-1/p - - */ - -public class DECAY_Series : Single_TSeries_Indicator { - private readonly bool _exp; - private double _pdecay, _ppdecay; - private readonly double _dfactor; - - public DECAY_Series(TSeries source, int period = 10, bool exponential= false, bool useNaN = false) : base(source, period, false) { - _exp = exponential; - _dfactor = (_exp)? 1.0 - 1.0 / (double)_p : 1/(double)_p; - _pdecay = _ppdecay = 0; - if (source.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - if (update) { _pdecay = _ppdecay; } - else { _ppdecay = _pdecay; } - - if (this.Count == 0) { _pdecay = TValue.v; } - double _decay = Math.Max(TValue.v, Math.Max((_exp)?_pdecay*_dfactor:_pdecay-_dfactor, 0)); - _pdecay = _decay; - - base.Add((TValue.t, _decay), update, _NaN); - } -} diff --git a/Calculations/Statistics/ENTROPY_Series.cs b/Calculations/Statistics/ENTROPY_Series.cs deleted file mode 100644 index f27ea6c7..00000000 --- a/Calculations/Statistics/ENTROPY_Series.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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) - ENTP = Σ(-P * Log(P) / Log(base)) - -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 - - */ - -public class ENTROPY_Series : Single_TSeries_Indicator -{ - public ENTROPY_Series(TSeries source, int period, double logbase = 2.0, bool useNaN = false) : base(source, period, useNaN) - { - this._logbase = logbase; - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly double _logbase; - private readonly System.Collections.Generic.List _buffer = new(); - private readonly System.Collections.Generic.List _buff2 = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sum = _buffer.Sum(); - - double _pp = this._buffer[this._buffer.Count - 1] / _sum; - double _ppp = -_pp * Math.Log(_pp) / Math.Log(this._logbase); - - Add_Replace_Trim(_buff2, _ppp, _p, update); - double _entp = _buff2.Sum(); - - base.Add((TValue.t, _entp), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/KURTOSIS_Series.cs b/Calculations/Statistics/KURTOSIS_Series.cs deleted file mode 100644 index ae1c93b2..00000000 --- a/Calculations/Statistics/KURTOSIS_Series.cs +++ /dev/null @@ -1,57 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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. - - The normal curve is called Mesokurtic curve. If the curve of a distribution is - more outlier prone (or heavier-tailed) than a normal or mesokurtic curve then - it is referred to as a Leptokurtic curve. If a curve is less outlier prone (or - lighter-tailed) than a normal curve, it is called as a platykurtic curve. - -Calculation: - sum4 = Σ(close-SMA)^4 - sum2 = (Σ(close-SMA)^2)^2 - KURT = length * (sum4/sum2) - -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/ - - */ - -public class KURTOSIS_Series : Single_TSeries_Indicator -{ - public KURTOSIS_Series(TSeries source, int period, double logbase = 2.0, bool useNaN = false) : base(source, period, useNaN) - { - this._logbase = logbase; - if (base._data.Count > 0) { base.Add(base._data); } - } - protected double _logbase; - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _n = this._buffer.Count; - double _avg = _buffer.Average(); - - double _s2 = 0; - double _s4 = 0; - for (int i = 0; i < this._buffer.Count; i++) - { - _s2 += (_buffer[i] - _avg) * (_buffer[i] - _avg); - _s4 += (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg); - } - - 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; - - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? Double.NaN : _kurt); - base.Add(result, update); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/MAD_Series.cs b/Calculations/Statistics/MAD_Series.cs deleted file mode 100644 index 8a032e4a..00000000 --- a/Calculations/Statistics/MAD_Series.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 - -Sources: - https://en.wikipedia.org/wiki/Average_absolute_deviation - - */ - -public class MAD_Series : Single_TSeries_Indicator -{ - public MAD_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - double _sma = _buffer.Average(); - - double _mad = 0; - for (int i = 0; i < _buffer.Count; i++) { _mad += Math.Abs(_buffer[i] - _sma); } - _mad /= this._buffer.Count; - - base.Add((TValue.t, _mad), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/MAPE_Series.cs b/Calculations/Statistics/MAPE_Series.cs deleted file mode 100644 index ca737cf1..00000000 --- a/Calculations/Statistics/MAPE_Series.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -MAPE: Mean Absolute Percentage Error - Measures the size of the error in percentage terms - -Calculation: - MAPE = Σ(|close – SMA| / |close|) / n - -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 - - */ - -public class MAPE_Series : Single_TSeries_Indicator -{ - public MAPE_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _mape = 0; - for (int i = 0; i < _buffer.Count; i++) { - _mape += (_buffer[i] != 0) ? Math.Abs(_buffer[i] - _sma) / Math.Abs(_buffer[i]) : double.PositiveInfinity; - } - _mape /= (_buffer.Count>0) ? _buffer.Count : 1; - - base.Add((TValue.t, _mape), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/MEDIAN_Series.cs b/Calculations/Statistics/MEDIAN_Series.cs deleted file mode 100644 index 0bbd6948..00000000 --- a/Calculations/Statistics/MEDIAN_Series.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace QuanTAlib; -using System; -using static System.Net.Mime.MediaTypeNames; - -/* -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. - - 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 - -Sources: - https://corporatefinanceinstitute.com/resources/knowledge/other/median/ - https://en.wikipedia.org/wiki/Median - - */ - -public class MEDIAN_Series : Single_TSeries_Indicator -{ - public MEDIAN_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - System.Collections.Generic.List _s = new(this._buffer); - _s.Sort(); - int _p1 = _s.Count / 2; - int _p2 = Math.Max(0, (_s.Count / 2) - 1); - double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2; - - base.Add((TValue.t, _med), update, _NaN); - } -} diff --git a/Calculations/Statistics/MSE_Series.cs b/Calculations/Statistics/MSE_Series.cs deleted file mode 100644 index 1dcdd6a9..00000000 --- a/Calculations/Statistics/MSE_Series.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 - - */ - -public class MSE_Series : Single_TSeries_Indicator -{ - public MSE_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _mse = 0; - for (int i = 0; i < _buffer.Count; i++) { _mse += (_buffer[i] - _sma) * (_buffer[i] - _sma); } - _mse /= this._buffer.Count; - - base.Add((TValue.t, _mse), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/SDEV_Series.cs b/Calculations/Statistics/SDEV_Series.cs deleted file mode 100644 index b85c3a16..00000000 --- a/Calculations/Statistics/SDEV_Series.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -SDEV: 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 - -Remark: - SDEV (Population Standard Deviation) is also known as a biased/uncorrected Standard Deviation. - For unbiased version that uses Bessel's correction, use SDEV instead. - - */ - -public class SDEV_Series : Single_TSeries_Indicator -{ - public SDEV_Series(TSeries source, int period=0, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _pvar = 0; - for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } - _pvar /= this._buffer.Count; - double _psdev = Math.Sqrt(_pvar); - - base.Add((TValue.t, _psdev), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/SMAPE_Series.cs b/Calculations/Statistics/SMAPE_Series.cs deleted file mode 100644 index dc0eaaa5..00000000 --- a/Calculations/Statistics/SMAPE_Series.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 - - */ - -public class SMAPE_Series : Single_TSeries_Indicator -{ - public SMAPE_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _smape = 0; - for (int i = 0; i < _buffer.Count; i++) { _smape += Math.Abs(_buffer[i] - _sma) / (Math.Abs(_buffer[i]) + Math.Abs(_sma)); } - _smape /= this._buffer.Count; - - base.Add((TValue.t, _smape), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/SSDEV_Series.cs b/Calculations/Statistics/SSDEV_Series.cs deleted file mode 100644 index ab882476..00000000 --- a/Calculations/Statistics/SSDEV_Series.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -SSDEV: (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 - - */ - -public class SSDEV_Series : Single_TSeries_Indicator -{ - public SSDEV_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _svar = 0; - for (int i = 0; i < this._buffer.Count; i++) { _svar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } - _svar /= (_buffer.Count > 1) ? _buffer.Count - 1 : 1; // Bessel's correction - double _ssdev = Math.Sqrt(_svar); - - base.Add((TValue.t, _ssdev), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/SVAR_Series.cs b/Calculations/Statistics/SVAR_Series.cs deleted file mode 100644 index a83d5deb..00000000 --- a/Calculations/Statistics/SVAR_Series.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -SVAR: 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 - Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction - -Remark: - SVAR is also known as the Unbiased Sample Variance, while VAR (Population Variance) is known as - the Biased Sample Variance. - - */ - -public class SVAR_Series : Single_TSeries_Indicator -{ - public SVAR_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _svar = 0; - for (int i = 0; i < this._buffer.Count; i++) { _svar += (this._buffer[i] - _sma) * (this._buffer[i] - _sma); } - _svar /= (this._buffer.Count > 1) ? this._buffer.Count - 1 : 1; // Bessel's correction - - base.Add((TValue.t, _svar), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/VAR_Series.cs b/Calculations/Statistics/VAR_Series.cs deleted file mode 100644 index 447ae16f..00000000 --- a/Calculations/Statistics/VAR_Series.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -VAR: Population Variance - Population variance without Bessel's correction - -Sources: - https://en.wikipedia.org/wiki/Variance - Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction - -Remark: - VAR (Population Variance) is also known as a biased Sample Variance. For unbiased - sample variance use SVAR instead. - - */ - -public class VAR_Series : Single_TSeries_Indicator -{ - public VAR_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _pvar = 0; - for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } - _pvar /= this._buffer.Count; - - base.Add((TValue.t, _pvar), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/WMAPE_Series.cs b/Calculations/Statistics/WMAPE_Series.cs deleted file mode 100644 index ff2a112a..00000000 --- a/Calculations/Statistics/WMAPE_Series.cs +++ /dev/null @@ -1,40 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -WMAPE: Weighted Mean Absolute Percentage Error - Measures the size of the error in percentage terms. Improves problems with MAPE - when there are zero or close-to-zero values because there would be a division by zero - or values of MAPE tending to infinity. - -Sources: - https://en.wikipedia.org/wiki/WMAPE - - */ - -public class WMAPE_Series : Single_TSeries_Indicator -{ - public WMAPE_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _div = 0; - double _wmape = 0; - for (int i = 0; i < _buffer.Count; i++) - { - _wmape += Math.Abs(_buffer[i] - _sma); - _div += Math.Abs(_buffer[i]); - } - _wmape = (_div!=0) ? _wmape/_div : double.PositiveInfinity; - - base.Add((TValue.t, _wmape), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/ZSCORE_Series.cs b/Calculations/Statistics/ZSCORE_Series.cs deleted file mode 100644 index fbaf02b9..00000000 --- a/Calculations/Statistics/ZSCORE_Series.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -ZSCORE: number of standard deviations from SMA - Z-score describes a value's relationship to the mean of a series, as measured in - terms of standard deviations from the mean. If a Z-score is 0, it indicates that - the data point's score is identical to the mean score. A Z-score of 1.0 would - indicate a value that is one standard deviation from the mean. Z-scores may be - positive or negative, with a positive value indicating the score is above the - mean and a negative score indicating it is below the mean. - -Sources: - https://en.wikipedia.org/wiki/Z-score - https://www.investopedia.com/terms/z/zscore.asp - -Calculation: - std = std * STDEV(close, length) - mean = SMA(close, length) - ZSCORE = (close - mean) / std - - */ - -public class ZSCORE_Series : Single_TSeries_Indicator -{ - public ZSCORE_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _pvar = 0; - for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } - _pvar /= this._buffer.Count; - double _psdev = Math.Sqrt(_pvar); - double _zscore = (_psdev == 0) ? double.NaN : (TValue.v - _sma) / _psdev; - - base.Add((TValue.t, _zscore), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/ALMA_Series.cs b/Calculations/Trends/ALMA_Series.cs deleted file mode 100644 index 30d755f5..00000000 --- a/Calculations/Trends/ALMA_Series.cs +++ /dev/null @@ -1,63 +0,0 @@ -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/ - - Discrepancy with Pandas-TA (but passes the validation with Skender.GetAlma) - - */ - -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) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - if (this._buffer.Count <= _p) - { - 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; - } - } - - double _weightedSum = 0; - for (int i = 0; i < this._buffer.Count; i++) - { _weightedSum += _weight[i] * _buffer[i]; } - double _alma = _weightedSum / _norm; - - base.Add((TValue.t, _alma), update, _NaN); - } -} diff --git a/Calculations/Momentum/CCI_Series.cs b/Calculations/Trends/CCI_Series.cs similarity index 100% rename from Calculations/Momentum/CCI_Series.cs rename to Calculations/Trends/CCI_Series.cs diff --git a/Calculations/Trends/DEMA_Series.cs b/Calculations/Trends/DEMA_Series.cs deleted file mode 100644 index 6dea06e5..00000000 --- a/Calculations/Trends/DEMA_Series.cs +++ /dev/null @@ -1,72 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; -using System.Runtime.CompilerServices; - -/* -DEMA: Double 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/ - -Remark: - ema1 = EMA(close, length) - ema2 = EMA(ema1, length) - DEMA = 2 * ema1 - ema2 - - */ - -public class DEMA_Series : Single_TSeries_Indicator -{ - private readonly double _k; - private int _len; - private readonly bool _useSMA; - private double _sum, _lastsum, _lastlastsum; - private double _lastema1, _lastlastema1; - private double _lastema2, _lastlastema2; - - public DEMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) - { - _k = 2.0 / (_p + 1); - _len = 0; - _useSMA = useSMA; - _sum = _lastema1 = _lastema2 =0; - if (_data.Count > 0) { base.Add(_data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - if (update) { - _lastsum = _lastlastsum; - _lastema1 = _lastlastema1; - _lastema2 = _lastlastema2; - } - else { - _lastlastsum = _lastsum; - _lastlastema1 = _lastema1; - _lastlastema2 = _lastema2; - _len++; - } - - double _ema1, _ema2, _dema; - if (this.Count == 0) { - _ema1 = _ema2 = _sum = TValue.v; - } - else if (_len <= _period && _useSMA && _period != 0) { - _sum += TValue.v; - _ema1 = _sum / Math.Min(_len, _period); - _ema2 = _ema1; - } - else { - _ema1 = (TValue.v - _lastema1) * _k + _lastema1; - _ema2 = (_ema1 - _lastema2) * _k + _lastema2; - } - _dema = 2*_ema1 - _ema2; - - _lastema1 = Double.IsNaN(_ema1)?_lastema1:_ema1; - _lastema2 = Double.IsNaN(_ema2)?_lastema2:_ema2; - - base.Add((TValue.t, _dema), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/DWMA_Series.cs b/Calculations/Trends/DWMA_Series.cs deleted file mode 100644 index 08d2ecb9..00000000 --- a/Calculations/Trends/DWMA_Series.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -DWMA: Double Weighted Moving Average - The weights are decreasing over the period with p^2 decay - and the most recent data has the heaviest weight. - - */ - -public class DWMA_Series : Single_TSeries_Indicator { - private readonly System.Collections.Generic.List _buffer1 = new(); - private readonly System.Collections.Generic.List _weights = new(); - public DWMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) { - for (int i = 0; i < this._p; i++) { - double _weight = (i + 1) * (i + 1); - this._weights.Add(_weight); - } - if (base._data.Count > 0) { base.Add(base._data); } - } - - public override void Add((System.DateTime t, double v) TValue, bool update) { - Add_Replace_Trim(_buffer1, TValue.v, _p, update); - double _wma1 = 0, _wsum = 0; - for (int i = 0; i < _buffer1.Count; i++) { - _wma1 += _buffer1[i] * _weights[i]; - _wsum += _weights[i]; - } - _wma1 /= _wsum; - - base.Add((TValue.t, _wma1), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/EMA_Series.cs b/Calculations/Trends/EMA_Series.cs deleted file mode 100644 index 6ce1d3a1..00000000 --- a/Calculations/Trends/EMA_Series.cs +++ /dev/null @@ -1,71 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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) - -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. - - */ - -public class EMA_Series : Single_TSeries_Indicator { - private double _k; - private double _lastema, _lastlastema; - private double _sum, _oldsum; - private int _len; - private readonly bool _useSMA; - - public EMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) { - _k = 2.0 / (_p + 1); - _sum = _oldsum = _lastema = _lastlastema = 0; - _len = 0; - _useSMA = useSMA; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - - if (update) { _lastema = _lastlastema; _sum = _oldsum; } - else { _lastlastema = _lastema; _oldsum = _sum; _len++; } - - double _ema = 0; - // when period = 0, create cumulative/additive series where _k is progressively larger - if (_period == 0) { _k = 2.0 / (_len + 1); } - - // the first value of the series - if (this.Count == 0) { - _ema = _sum = TValue.v; - } - // if SMA is used for seeding, calculate SMA within period - else if (_len <= _period && _useSMA && _period != 0) { - _sum += TValue.v; - if (_period != 0 && _len > _period) { - _sum -= (_data[base.Count - _period - (update ? 1 : 0)].v); - } - _ema = _sum / Math.Min(_len, _period); - } - // calculate EMA out from last EMA and factor k - else { - _ema = _k * (TValue.v - _lastema) + _lastema; - } - _lastema = Double.IsNaN(_ema)?_lastema:_ema; - - base.Add((TValue.t, _ema), update, _NaN); - } - public void Reset() { - _sum = _oldsum = _lastema = _lastlastema = 0; - _len = 0; - } -} \ No newline at end of file diff --git a/Calculations/Trends/FMA_Series.cs b/Calculations/Trends/FMA_Series.cs deleted file mode 100644 index c43a6679..00000000 --- a/Calculations/Trends/FMA_Series.cs +++ /dev/null @@ -1,59 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -FMA: Fibonacci Moving Average - FMA calculates the average across multiple EMAs with periods following Fibonacci sequence - (skipping initial Fibonacci numbers of 1, 1, 2) 3, 5, 8, 13, 21, 34... - - FMA(n) = Average(EMA(3), EMA(5), EMA(8), ema(13), ... EMA(n-th Fib)) - -Sources: - https://kaabar-sofien.medium.com/the-fibonacci-moving-average-the-full-guide-60e718117595 - https://usethinkscript.com/threads/fibonacci-moving-average.8099/ - - */ - -public class FMA_Series : Single_TSeries_Indicator { - readonly double[,] fib; - double _oldsum; - readonly int _len; - - public FMA_Series(TSeries source, int period) : base(source, period, false) { - _len = period; - fib = new double[_len, 4]; - int a = 3; - int b = 5; - int f = 0; - fib[0, 0] = 2 / ((double)a - 1); - if (_len > 1) { fib[1, 0] = 2 / ((double)b - 1); } - if (_len > 2) { - for (int i = 2; i < _len; i++) { - f = a + b; - a = b; - b = f; - fib[i, 0] = 2 / ((double)f - 1); - } - } - _oldsum = 0; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - double _sum = 0; - for (int i = 0; i < _len; i++) { - if (update) { fib[i, 1] = fib[i, 3]; _sum = _oldsum; } - else { fib[i, 3] = fib[i, 1]; _oldsum = _sum; } - - if (this.Count == 0) { fib[i, 1] = TValue.v; } - else { - fib[i, 2] = fib[i, 0] * (TValue.v - fib[i, 1]) + fib[i, 1]; - fib[i, 1] = fib[i, 2]; - } - _sum += fib[i, 1]; - } - - double _fma = _sum / _len; - base.Add((TValue.t, _fma), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/HEMA_Series.cs b/Calculations/Trends/HEMA_Series.cs deleted file mode 100644 index dcb9d560..00000000 --- a/Calculations/Trends/HEMA_Series.cs +++ /dev/null @@ -1,57 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -HEMA: Hull-EMA Moving Average - a hybrid indicator - Modified HUll Moving Average; instead of using WMA (Weighted MA) for calculation, - 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 -{ - public HEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - this._k1 = 4 / ((period * 0.5) + 1); - this._k2 = 3 / (double)(period + 1); - this._k3 = 2 / (Math.Sqrt(period) + 1); - this._lastema1 = this._lastlastema1 = double.NaN; - this._lastema2 = this._lastlastema2 = double.NaN; - this._lastema3 = this._lastlastema3 = double.NaN; - - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly double _k1, _k2, _k3; - private double _lastema1, _lastlastema1; - private double _lastema2, _lastlastema2; - private double _lastema3, _lastlastema3; - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - if (update) - { - this._lastema1 = this._lastlastema1; - this._lastema2 = this._lastlastema2; - this._lastema3 = this._lastlastema3; - } - double _ema1 = System.Double.IsNaN(this._lastema1) ? TValue.v : TValue.v * this._k1 + this._lastema1 * (1 - this._k1); - double _ema2 = System.Double.IsNaN(this._lastema2) ? TValue.v : TValue.v * this._k2 + this._lastema2 * (1 - this._k2); - - double _rawhema = (2 * _ema1) - _ema2; - double _ema3 = System.Double.IsNaN(this._lastema3) ? _rawhema : _rawhema * this._k3 + this._lastema3 * (1 - this._k3); - - this._lastlastema1 = this._lastema1; - this._lastlastema2 = this._lastema2; - this._lastlastema3 = this._lastema3; - this._lastema1 = _ema1; - this._lastema2 = _ema2; - this._lastema3 = _ema3; - - base.Add((TValue.t, _ema3), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/HMA_Series.cs b/Calculations/Trends/HMA_Series.cs deleted file mode 100644 index 8a522fba..00000000 --- a/Calculations/Trends/HMA_Series.cs +++ /dev/null @@ -1,119 +0,0 @@ -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. - -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 -{ - private readonly int _p; - private readonly bool _NaN; - private readonly TSeries _data; - private double _wma1, _wma2; - private readonly System.Collections.Generic.List _buf1 = new(); - private readonly System.Collections.Generic.List _buf2 = new(); - private readonly System.Collections.Generic.List _buf3 = new(); - private readonly System.Collections.Generic.List _weights = new(); - - public HMA_Series(TSeries source, int period, bool useNaN = false) - { - this._p = period; - this._data = source; - this._NaN = useNaN; - for (int i = 0; i < this._p; i++) - { - this._weights.Add(i + 1); - } - - source.Pub += this.Sub; - if (source.Count > 0) - { - for (int i = 0; i < source.Count; i++) - { - this.Add(source[i], false); - } - } - } - public new void Add((System.DateTime t, double v) data, bool update = false) - { - if (update) - { - this._buf1[this._buf1.Count - 1] = data.v; - this._buf2[this._buf2.Count - 1] = data.v; - } - else - { - this._buf1.Add(data.v); - this._buf2.Add(data.v); - } - if (this._buf1.Count > (int)((double)this._p / 2)) - { - this._buf1.RemoveAt(0); - } - if (this._buf2.Count > this._p) - { - this._buf2.RemoveAt(0); - } - - this._wma1 = 0; - for (int i = 0; i < this._buf1.Count; i++) - { - this._wma1 += this._buf1[i] * this._weights[i]; - } - this._wma1 /= (this._buf1.Count * (this._buf1.Count + 1)) * 0.5; - - this._wma2 = 0; - for (int i = 0; i < this._buf2.Count; i++) - { - this._wma2 += this._buf2[i] * this._weights[i]; - } - this._wma2 /= (this._buf2.Count * (this._buf2.Count + 1)) * 0.5; - - if (update) - { - this._buf3[this._buf3.Count - 1] = 2 * this._wma1 - this._wma2; - } - else - { - this._buf3.Add(2 * this._wma1 - this._wma2); - } - - if (this._buf3.Count > (int)Math.Sqrt(this._p)) - { - this._buf3.RemoveAt(0); - } - - double _hma = 0; - for (int i = 0; i < this._buf3.Count; i++) - { - _hma += this._buf3[i] * this._weights[i]; - } - - _hma /= (this._buf3.Count * (this._buf3.Count + 1)) * 0.5; - - (System.DateTime t, double v) result = - (data.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _hma); - base.Add(result, update); - } - public void Add(bool update = false) - { - this.Add(this._data[this._data.Count - 1], update); - } - public new void Sub(object source, TSeriesEventArgs e) - { - this.Add(this._data[this._data.Count - 1], e.update); - } -} diff --git a/Calculations/Trends/KAMA_Series.cs b/Calculations/Trends/KAMA_Series.cs deleted file mode 100644 index 808ce8c7..00000000 --- a/Calculations/Trends/KAMA_Series.cs +++ /dev/null @@ -1,64 +0,0 @@ -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; - _lastkama = _lastlastkama; - } - else { - _buffer.Add(TValue.v); - _lastlastkama = _lastkama; - } - if (_buffer.Count > _p + 1) { _buffer.RemoveAt(0); } - - double _kama = 0; - if (this.Count < this._p) { _kama = TValue.v; } - 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))); - } - _lastkama = _kama; - base.Add((TValue.t, _kama), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/MAMA_Series.cs b/Calculations/Trends/MAMA_Series.cs index 624321a8..5a04d341 100644 --- a/Calculations/Trends/MAMA_Series.cs +++ b/Calculations/Trends/MAMA_Series.cs @@ -15,105 +15,144 @@ Sources: */ -public class MAMA_Series : Single_TSeries_Indicator -{ - public MAMA_Series(TSeries source, double fastlimit = 0.5, double slowlimit = 0.05, bool useNaN = false) : base(source, period: 5, useNaN) - { - fastl = fastlimit; - slowl = slowlimit; - Fama = new(); - if (base._data.Count > 0) { base.Add(base._data); } - } - private double sumPr, jI, jQ; - readonly double fastl, slowl; - private (double i, double i1, double i2, double i3, double i4, double i5, double i6, double io) pr, i1, q1, sm, dt; - private (double i, double i1, double io) i2, q2, re, im, pd, ph, mama, fama; - public TSeries Fama { get; } - public override void Add((System.DateTime t, double v) TValue, bool update) - { +public class MAMA_Series : Single_TSeries_Indicator { + public MAMA_Series(TSeries source, double fastlimit = 0.5, double slowlimit = 0.05, bool useNaN = false) : base(source, 5, useNaN) { + fastl = fastlimit; + slowl = slowlimit; + Fama = new TSeries(); + if (_data.Count > 0) { + base.Add(_data); + } + } - if (!update) { - // roll forward (oldx = x) - pr.io = pr.i6; pr.i6 = pr.i5; pr.i5 = pr.i4; pr.i4 = pr.i3; pr.i3 = pr.i2; pr.i2 = pr.i1; pr.i1 = pr.i; - i1.io = i1.i6; i1.i6 = i1.i5; i1.i5 = i1.i4; i1.i4 = i1.i3; i1.i3 = i1.i2; i1.i2 = i1.i1; i1.i1 = i1.i; - q1.io = q1.i6; q1.i6 = q1.i5; q1.i5 = q1.i4; q1.i4 = q1.i3; q1.i3 = q1.i2; q1.i2 = q1.i1; q1.i1 = q1.i; - dt.io = dt.i6; dt.i6 = dt.i5; dt.i5 = dt.i4; dt.i4 = dt.i3; dt.i3 = dt.i2; dt.i2 = dt.i1; dt.i1 = dt.i; - sm.io = sm.i6; sm.i6 = sm.i5; sm.i5 = sm.i4; sm.i4 = sm.i3; sm.i3 = sm.i2; sm.i2 = sm.i1; sm.i1 = sm.i; - i2.io = i2.i1; i2.i1 = i2.i; - q2.io = q2.i1; q2.i1 = q2.i; - re.io = re.i1; re.i1 = re.i; - im.io = im.i1; im.i1 = im.i; - pd.io = pd.i1; pd.i1 = pd.i; - ph.io = ph.i1; ph.i1 = ph.i; - mama.io = mama.i1; mama.i1 = mama.i; - fama.io = fama.i1; fama.i1 = fama.i; - } - int i = base.Count; - pr.i = TValue.v; - if (i > 5) { - double adj = (0.075 * pd.i1) + 0.54; + private double sumPr, jI, jQ; + private readonly double fastl, slowl; + private (double i, double i1, double i2, double i3, double i4, double i5, double i6, double io) pr, i1, q1, sm, dt; + private (double i, double i1, double io) i2, q2, re, im, pd, ph, mama, fama; + public TSeries Fama { get; } - // smooth and detrender - sm.i = ((4 * pr.i) + (3 * pr.i1) + (2 * pr.i2) + pr.i3) / 10; - dt.i = ((0.0962 * sm.i) + (0.5769 * sm.i2) - (0.5769 * sm.i4) - (0.0962 * sm.i6)) * adj; + public override void Add((DateTime t, double v) TValue, bool update) { + if (!update) { + // roll forward (oldx = x) + pr.io = pr.i6; + pr.i6 = pr.i5; + pr.i5 = pr.i4; + pr.i4 = pr.i3; + pr.i3 = pr.i2; + pr.i2 = pr.i1; + pr.i1 = pr.i; + i1.io = i1.i6; + i1.i6 = i1.i5; + i1.i5 = i1.i4; + i1.i4 = i1.i3; + i1.i3 = i1.i2; + i1.i2 = i1.i1; + i1.i1 = i1.i; + q1.io = q1.i6; + q1.i6 = q1.i5; + q1.i5 = q1.i4; + q1.i4 = q1.i3; + q1.i3 = q1.i2; + q1.i2 = q1.i1; + q1.i1 = q1.i; + dt.io = dt.i6; + dt.i6 = dt.i5; + dt.i5 = dt.i4; + dt.i4 = dt.i3; + dt.i3 = dt.i2; + dt.i2 = dt.i1; + dt.i1 = dt.i; + sm.io = sm.i6; + sm.i6 = sm.i5; + sm.i5 = sm.i4; + sm.i4 = sm.i3; + sm.i3 = sm.i2; + sm.i2 = sm.i1; + sm.i1 = sm.i; + i2.io = i2.i1; + i2.i1 = i2.i; + q2.io = q2.i1; + q2.i1 = q2.i; + re.io = re.i1; + re.i1 = re.i; + im.io = im.i1; + im.i1 = im.i; + pd.io = pd.i1; + pd.i1 = pd.i; + ph.io = ph.i1; + ph.i1 = ph.i; + mama.io = mama.i1; + mama.i1 = mama.i; + fama.io = fama.i1; + fama.i1 = fama.i; + } - // in-phase and quadrature - q1.i = ((0.0962 * dt.i) + (0.5769 * dt.i2) - (0.5769 * dt.i4) - (0.0962 * dt.i6)) * adj; - i1.i = dt.i3; + var i = Count; + pr.i = TValue.v; + if (i > 5) { + var adj = 0.075 * pd.i1 + 0.54; - // advance the phases by 90 degrees - jI = ((0.0962 * i1.i) + (0.5769 * i1.i2) - (0.5769 * i1.i4) - (0.0962 * i1.i6)) * adj; - jQ = ((0.0962 * q1.i) + (0.5769 * q1.i2) - (0.5769 * q1.i4) - (0.0962 * q1.i6)) * adj; + // smooth and detrender + sm.i = (4 * pr.i + 3 * pr.i1 + 2 * pr.i2 + pr.i3) / 10; + dt.i = (0.0962 * sm.i + 0.5769 * sm.i2 - 0.5769 * sm.i4 - 0.0962 * sm.i6) * adj; - // phasor addition for 3-bar averaging - i2.i = i1.i - jQ; - q2.i = q1.i + jI; + // in-phase and quadrature + q1.i = (0.0962 * dt.i + 0.5769 * dt.i2 - 0.5769 * dt.i4 - 0.0962 * dt.i6) * adj; + i1.i = dt.i3; - i2.i = (0.2 * i2.i) + (0.8 * i2.i1); // smoothing it - q2.i = (0.2 * q2.i) + (0.8 * q2.i1); + // advance the phases by 90 degrees + jI = (0.0962 * i1.i + 0.5769 * i1.i2 - 0.5769 * i1.i4 - 0.0962 * i1.i6) * adj; + jQ = (0.0962 * q1.i + 0.5769 * q1.i2 - 0.5769 * q1.i4 - 0.0962 * q1.i6) * adj; - // homodyne discriminator - re.i = (i2.i * i2.i1) + (q2.i * q2.i1); - im.i = (i2.i * q2.i1) - (q2.i * i2.i1); + // phasor addition for 3-bar averaging + i2.i = i1.i - jQ; + q2.i = q1.i + jI; - re.i = (0.2 * re.i) + (0.8 * re.i1); // smoothing it - im.i = (0.2 * im.i) + (0.8 * im.i1); + i2.i = 0.2 * i2.i + 0.8 * i2.i1; // smoothing it + q2.i = 0.2 * q2.i + 0.8 * q2.i1; - // calculate period - pd.i = (im.i != 0 && re.i != 0) ? (6.283185307179586 / Math.Atan(im.i / re.i)) : 0d; + // homodyne discriminator + re.i = i2.i * i2.i1 + q2.i * q2.i1; + im.i = i2.i * q2.i1 - q2.i * i2.i1; - // adjust period to thresholds - pd.i = (pd.i > 1.5 * pd.i1) ? 1.5 * pd.i1 : pd.i; - pd.i = (pd.i < 0.67 * pd.i1) ? 0.67 * pd.i1 : pd.i; - pd.i = (pd.i < 6d) ? 6d : pd.i; - pd.i = (pd.i > 50d) ? 50d : pd.i; + re.i = 0.2 * re.i + 0.8 * re.i1; // smoothing it + im.i = 0.2 * im.i + 0.8 * im.i1; - // smooth the period - pd.i = (0.2 * pd.i) + (0.8 * pd.i1); + // calculate period + pd.i = im.i != 0 && re.i != 0 ? 6.283185307179586 / Math.Atan(im.i / re.i) : 0d; - // determine phase position - ph.i = (i1.i != 0) ? Math.Atan(q1.i / i1.i) * 57.29577951308232 : 0; + // adjust period to thresholds + pd.i = pd.i > 1.5 * pd.i1 ? 1.5 * pd.i1 : pd.i; + pd.i = pd.i < 0.67 * pd.i1 ? 0.67 * pd.i1 : pd.i; + pd.i = pd.i < 6d ? 6d : pd.i; + pd.i = pd.i > 50d ? 50d : pd.i; - // change in phase - double delta = Math.Max(ph.i1 - ph.i, 1d); + // smooth the period + pd.i = 0.2 * pd.i + 0.8 * pd.i1; - // adaptive alpha value - double alpha = Math.Max(fastl / delta, slowl); + // determine phase position + ph.i = i1.i != 0 ? Math.Atan(q1.i / i1.i) * 57.29577951308232 : 0; - // final indicators - mama.i = ((alpha * pr.i) + ((1d - alpha) * mama.i1)); - fama.i = ((0.5d * alpha * mama.i) + ((1d - (0.5d * alpha)) * fama.i1)); - } - else { - sumPr += pr.i; - pd.i = sm.i = dt.i = i1.i = q1.i = i2.i = q2.i = re.i = im.i = ph.i = 0; - mama.i = fama.i = sumPr / (i+1); - } + // change in phase + var delta = Math.Max(ph.i1 - ph.i, 1d); - base.Add((TValue.t, mama.i), update, _NaN); - var result = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : fama.i); - Fama.Add(result, update); - } + // adaptive alpha value + var alpha = Math.Max(fastl / delta, slowl); + + // final indicators + mama.i = alpha * pr.i + (1d - alpha) * mama.i1; + fama.i = 0.5d * alpha * mama.i + (1d - 0.5d * alpha) * fama.i1; + } + else { + sumPr += pr.i; + pd.i = sm.i = dt.i = i1.i = q1.i = i2.i = q2.i = re.i = im.i = ph.i = 0; + mama.i = fama.i = sumPr / (i + 1); + } + + base.Add((TValue.t, mama.i), update, _NaN); + var result = (TValue.t, Count < _p - 1 && _NaN ? double.NaN : fama.i); + Fama.Add(result, update); + } } diff --git a/Calculations/Trends/RMA_Series.cs b/Calculations/Trends/RMA_Series.cs deleted file mode 100644 index f7059c51..00000000 --- a/Calculations/Trends/RMA_Series.cs +++ /dev/null @@ -1,56 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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. - -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 - -Issues: - Pandas-TA library calculates RMA using straight Exponential Weighted Mean: - pandas.ewm().mean() and returns incorrect first (period) of bars compared to - published formula. This implementation passess the validation test in Wilder's book. - - */ - -public class RMA_Series : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer = new(); - private readonly double _k, _k1m; - private double _lastema, _lastlastema; - - public RMA_Series(TSeries 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 (_data.Count > 0) { base.Add(_data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - double _ema; - if (update) { this._lastema = this._lastlastema; } - - if (this.Count < this._p) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - _ema = _buffer.Average(); - } - else - { - _ema = (TValue.v * _k) + (_lastema * _k1m); - } - - this._lastlastema = this._lastema; - this._lastema = _ema; - - base.Add((TValue.t, _ema), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/SMA_Series.cs b/Calculations/Trends/SMA_Series.cs deleted file mode 100644 index 84c8395d..00000000 --- a/Calculations/Trends/SMA_Series.cs +++ /dev/null @@ -1,44 +0,0 @@ -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 - -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 (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 { - private double _sum, _oldsum; - private int _len; - - public SMA_Series(TSeries source, int period = 0, bool useNaN = false) : base(source, period, false) { - _sum = _oldsum = 0; - _len = 0; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - if (update) { _sum = _oldsum; } - else { _oldsum = _sum; _len++; } - - _sum += TValue.v; - if (_period != 0 && _len > _period) { - _sum -= (_data[base.Count - _period - (update ? 1 : 0)].v); - } - double _div = (_period == 0) ? _len : Math.Min(_len, _period); - base.Add((TValue.t, _sum / _div), update, _NaN); - } - public void Reset() { - _sum = _oldsum = 0; - _len = 0; - } -} diff --git a/Calculations/Trends/SMMA_Series.cs b/Calculations/Trends/SMMA_Series.cs deleted file mode 100644 index 27d3bfcd..00000000 --- a/Calculations/Trends/SMMA_Series.cs +++ /dev/null @@ -1,51 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -SMMA: Smoothed Moving Average - The Smoothed Moving Average (SMMA) is a combination of a SMA and an EMA. It gives the recent prices - an equal weighting as the historic prices as it takes all available price data into account. - The main advantage of a smoothed moving average is that it removes short-term fluctuations. - - SMMA(i) = (SMMA-1*(N-1) + CLOSE (i)) / N - -Sources: - https://blog.earn2trade.com/smoothed-moving-average - https://guide.traderevolution.com/traderevolution/mobile-applications/phone/android/technical-indicators/moving-averages/smma-smoothed-moving-average - https://www.chartmill.com/documentation/technical-analysis-indicators/217-MOVING-AVERAGES-%7C-The-Smoothed-Moving-Average-%28SMMA%29 - - */ - -public class SMMA_Series : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer = new(); - private double _lastsmma, _lastlastsmma; - - public SMMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - this._lastsmma = this._lastlastsmma = double.NaN; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - double _smma = 0; - if (update) { this._lastsmma = this._lastlastsmma; } - - if (this.Count < this._p) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - _smma = _buffer.Average(); - } - else - { - _smma = ((_lastsmma * (_p-1)) + TValue.v) / _p ; - } - - this._lastlastsmma = this._lastsmma; - this._lastsmma = _smma; - - base.Add((TValue.t, _smma), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/T3_Series.cs b/Calculations/Trends/T3_Series.cs deleted file mode 100644 index 4f598993..00000000 --- a/Calculations/Trends/T3_Series.cs +++ /dev/null @@ -1,100 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; -using System.Numerics; - -/* -T3: Tillson T3 Moving Average - Tim Tillson described it in "Technical Analysis of Stocks and Commodities", January 1998 in the - article "Better Moving Averages". Tillson’s moving average becomes a popular indicator of - technical analysis as it gets less lag with the price chart and its curve is considerably smoother. - -Sources: - https://technicalindicators.net/indicators-technical-analysis/150-t3-moving-average - http://www.binarytribune.com/forex-trading-indicators/t3-moving-average-indicator/ - - */ -public class T3_Series : Single_TSeries_Indicator { - private readonly double _k, _k1m, _c1, _c2, _c3, _c4; - private readonly System.Collections.Generic.List _buffer1 = new(); - private readonly System.Collections.Generic.List _buffer2 = new(); - private readonly System.Collections.Generic.List _buffer3 = new(); - private readonly System.Collections.Generic.List _buffer4 = new(); - private readonly System.Collections.Generic.List _buffer5 = new(); - private readonly System.Collections.Generic.List _buffer6 = new(); - - private double _lastema1, _lastema2, _lastema3, _lastema4, _lastema5, _lastema6; - private double _llastema1, _llastema2, _llastema3, _llastema4, _llastema5, _llastema6; - private readonly bool _useSMA; - - public T3_Series(TSeries source, int period, double vfactor = 0.7, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) { - double _a = vfactor; //0.7; //0.618 - _c1 = -_a * _a * _a; - _c2 = 3 * _a * _a + 3 * _a * _a * _a; - _c3 = -6 * _a * _a - 3 * _a - 3 * _a * _a * _a; - _c4 = 1 + 3 * _a + _a * _a * _a + 3 * _a * _a; - - _k = 2.0 / (_p + 1); - _k1m = 1.0 - _k; - _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = _lastema4 = _llastema4 = _lastema5 = _llastema5 = _lastema5 = _llastema5 = 0; - _useSMA = useSMA; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - double _ema1, _ema2, _ema3, _ema4, _ema5, _ema6; - if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; _lastema4 = _llastema4; _lastema5 = _llastema5; _lastema6 = _llastema6; } - else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; _llastema4 = _lastema4; _llastema5 = _lastema5; _llastema6 = _lastema6; } - - if (this.Count == 0) { _lastema1 = _lastema2 = _lastema3 = _lastema4 = _lastema5 = _lastema6 = TValue.v; } - - if ((this.Count < _p) && _useSMA) { - Add_Replace(_buffer1, TValue.v, update); - _ema1 = 0; - for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; } - _ema1 /= _buffer1.Count; - - Add_Replace(_buffer2, _ema1, update); - _ema2 = 0; - for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; } - _ema2 /= _buffer2.Count; - - Add_Replace(_buffer3, _ema2, update); - _ema3 = 0; - for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; } - _ema3 /= _buffer3.Count; - - Add_Replace(_buffer4, _ema3, update); - _ema4 = 0; - for (int i = 0; i < _buffer4.Count; i++) { _ema4 += _buffer4[i]; } - _ema4 /= _buffer4.Count; - - Add_Replace(_buffer5, _ema4, update); - _ema5 = 0; - for (int i = 0; i < _buffer5.Count; i++) { _ema5 += _buffer5[i]; } - _ema5 /= _buffer5.Count; - - Add_Replace(_buffer6, _ema5, update); - _ema6 = 0; - for (int i = 0; i < _buffer6.Count; i++) { _ema6 += _buffer6[i]; } - _ema6 /= _buffer6.Count; - } - 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); - _ema4 = (_ema3 * this._k) + (this._lastema4 * this._k1m); - _ema5 = (_ema4 * this._k) + (this._lastema5 * this._k1m); - _ema6 = (_ema5 * this._k) + (this._lastema6 * this._k1m); - } - _lastema1 = _ema1; - _lastema2 = _ema2; - _lastema3 = _ema3; - _lastema4 = _ema4; - _lastema5 = _ema5; - _lastema6 = _ema6; - - double _T3 = _c1 * _ema6 + _c2 * _ema5 + _c3 * _ema4 + _c4 * _ema3; - base.Add((TValue.t, _T3), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/TEMA_Series.cs b/Calculations/Trends/TEMA_Series.cs deleted file mode 100644 index 71f84698..00000000 --- a/Calculations/Trends/TEMA_Series.cs +++ /dev/null @@ -1,70 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -TEMA: Triple 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/ - -Remark: - ema1 = EMA(close, length) - ema2 = EMA(ema1, length) - ema3 = EMA(ema2, length) - TEMA = 3 * (ema1 - ema2) + ema3 - - */ - -public class TEMA_Series : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer = new(); - private readonly double _k, _k1m; - private double _lastema1, _lastlastema1; - private double _lastema2, _lastlastema2; - private double _lastema3, _lastlastema3; - - public TEMA_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; - if (_data.Count > 0) { base.Add(_data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - if (update) - { - this._lastema1 = this._lastlastema1; - this._lastema2 = this._lastlastema2; - this._lastema3 = this._lastlastema3; - } - - double _ema1, _ema2, _ema3; - - if (this.Count < this._p) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - _ema1 = _ema2 = _ema3 = _sma; - } - 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); - } - - double _tema = (3 * (_ema1 - _ema2)) + _ema3; - - this._lastlastema1 = this._lastema1; - this._lastlastema2 = this._lastema2; - this._lastlastema3 = this._lastema3; - this._lastema1 = _ema1; - this._lastema2 = _ema2; - this._lastema3 = _ema3; - - base.Add((TValue.t, _tema), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/TRIMA_Series.cs b/Calculations/Trends/TRIMA_Series.cs deleted file mode 100644 index 7a082b7e..00000000 --- a/Calculations/Trends/TRIMA_Series.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 = _buffer1.Average(); - - if (update) { _buffer2[_buffer2.Count - 1] = _sma1; } else { _buffer2.Add(_sma1); } - if (_buffer2.Count > this._p1a && this._p1a != 0) { _buffer2.RemoveAt(0); } - double _trima = _buffer2.Average(); - - base.Add((TValue.t, _trima), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/TRIX_Series.cs b/Calculations/Trends/TRIX_Series.cs deleted file mode 100644 index 7815048c..00000000 --- a/Calculations/Trends/TRIX_Series.cs +++ /dev/null @@ -1,75 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; -using System.Numerics; - -/* -TRIX: Triple Exponential Average - Developed by Jack Hutson in the early 1980s, the triple exponential average (TRIX) - has become a popular technical analysis tool to aid chartists in spotting diversions -and directional cues in stock trading patterns. - -Sources: - https://www.investopedia.com/terms/t/trix.asp - - */ -public class TRIX_Series : Single_TSeries_Indicator -{ - private readonly double _k, _k1m; - private readonly System.Collections.Generic.List _buffer1 = new(); - private readonly System.Collections.Generic.List _buffer2 = new(); - private readonly System.Collections.Generic.List _buffer3 = new(); - - private double _lastema1, _lastema2, _lastema3; - private double _llastema1, _llastema2, _llastema3; - private readonly bool _useSMA; - - public TRIX_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) - { - - _k = 2.0 / (_p + 1); - _k1m = 1.0 - _k; - _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = 0; - _useSMA = useSMA; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - double _ema1, _ema2, _ema3; - if (this.Count == 0) { _lastema1 = _lastema2 = _lastema3 = TValue.v; } - - if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; } - else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; } - - if ((this.Count < _p) && _useSMA) - { - Add_Replace(_buffer1, TValue.v, update); - _ema1 = 0; - for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; } - _ema1 /= _buffer1.Count; - - Add_Replace(_buffer2, _ema1, update); - _ema2 = 0; - for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; } - _ema2 /= _buffer2.Count; - - Add_Replace(_buffer3, _ema2, update); - _ema3 = 0; - for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; } - _ema3 /= _buffer3.Count; - } - 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); - } - double _trix = 100 * (_ema3 - _lastema3) / _lastema3; - _lastema1 = _ema1; - _lastema2 = _ema2; - _lastema3 = _ema3; - - base.Add((TValue.t, _trix), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/WMA_Series.cs b/Calculations/Trends/WMA_Series.cs deleted file mode 100644 index 2b835b7f..00000000 --- a/Calculations/Trends/WMA_Series.cs +++ /dev/null @@ -1,35 +0,0 @@ -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. - -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 -{ - public WMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - for (int i = 0; i < this._p; i++) { this._weights.Add(i + 1); } - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - private readonly System.Collections.Generic.List _weights = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - double _wma = 0; - for (int i = 0; i < _buffer.Count; i++) { _wma += _buffer[i] * this._weights[i]; } - _wma /= (this._buffer.Count * (this._buffer.Count + 1)) * 0.5; - - base.Add((TValue.t, _wma), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/ZLEMA_Series.cs b/Calculations/Trends/ZLEMA_Series.cs deleted file mode 100644 index a72da3ce..00000000 --- a/Calculations/Trends/ZLEMA_Series.cs +++ /dev/null @@ -1,62 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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, _lastema_o; - private int _llag; - private readonly bool _useSMA; - - public ZLEMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) - { - this._k = 2.0 / (this._p + 1); - this._k1m = 1.0 - this._k; - this._lastema = this._lastema_o = double.NaN; - _llag = (int)((_p-1) * 0.5); - _useSMA = useSMA; - if (_data.Count > 0) { base.Add(_data); } - } - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - int _lag = Math.Max(this.Count-_llag, 0); - if (update) { - _lastema = _lastema_o; _lag--; - } else { - _lastema_o = _lastema; - } - double _zl = TValue.v + (TValue.v - _data[_lag].v); - double _ema = 0; - - if (this.Count < this._p && _useSMA) { - Add_Replace_Trim(_buffer, _zl, _p, update); - _ema = _buffer.Average(); - } else { - _ema = (_zl * _k) + (_lastema * _k1m); - } - _lastema = _ema; - - base.Add((TValue.t, _ema), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Volatility/ATRP_Series.cs b/Calculations/Volatility/ATRP_Series.cs index 086db3db..3f4457ea 100644 --- a/Calculations/Volatility/ATRP_Series.cs +++ b/Calculations/Volatility/ATRP_Series.cs @@ -19,7 +19,7 @@ public class ATRP_Series : Single_TBars_Indicator { public ATRP_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) { _period = period; - _k = 1.0 / (double)(_p); + _k = 1.0 / (double)(_period); _lastatr = _lastlastatr = _cm1 = _lastcm1 = _sum = _oldsum = 0; if (this._bars.Count > 0) { base.Add(this._bars); } } diff --git a/Calculations/Volatility/CMO_Series.cs b/Calculations/Volatility/CMO_Series.cs deleted file mode 100644 index 6cabc235..00000000 --- a/Calculations/Volatility/CMO_Series.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -CMO: Chande Momentum Oscillator - Chande Momentum Oscillator (also known as CMO indicator) was developed by Tushar S. Chande - CMO is similar to other momentum oscillators (e.g. RSI or Stochastics). Alike RSI oscillator, - the CMO values move in the range from -100 to +100 points and its aim is to detect the - overbought and oversold market conditions. CMO calculates the price momentum on both the up - days as well as the down days. The CMO calculation is based on non-smoothed price values - meaning that it can reach its extremes more frequently and the short-time swings are more visible. - -Sources: - https://www.technicalindicators.net/indicators-technical-analysis/144-cmo-chande-momentum-oscillator - - */ - -public class CMO_Series : Single_TSeries_Indicator { - private readonly System.Collections.Generic.List _buff_up = new(); - private readonly System.Collections.Generic.List _buff_dn = new(); - private double _plast_value, _last_value; - - public CMO_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) { - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - if (this.Count == 0) { _plast_value = _last_value = TValue.v; } - if (update) {_last_value = _plast_value;} else {_plast_value = _last_value;} - - Add_Replace_Trim(_buff_up, (TValue.v > _last_value) ? TValue.v-_last_value : 0, _p, update); - Add_Replace_Trim(_buff_dn, (TValue.v < _last_value) ? _last_value-TValue.v : 0, _p, update); - _last_value = TValue.v; - - double _cmo_up = 0; - double _cmo_dn = 0; - for (int i = 0; i < Math.Min(_buff_up.Count, _buff_dn.Count); i++) { - _cmo_up += _buff_up[i]; - _cmo_dn += _buff_dn[i]; - } - - double _cmo = 100 * (_cmo_up - _cmo_dn) / (_cmo_up + _cmo_dn); - if (_cmo_up + _cmo_dn == 0) {_cmo = 0;} - base.Add((TValue.t, _cmo), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Volume/OBV_Series.cs b/Calculations/Volatility/OBV_Series.cs similarity index 100% rename from Calculations/Volume/OBV_Series.cs rename to Calculations/Volatility/OBV_Series.cs diff --git a/Calculations/Volatility/RSI_Series.cs b/Calculations/Volatility/RSI_Series.cs deleted file mode 100644 index 0805df35..00000000 --- a/Calculations/Volatility/RSI_Series.cs +++ /dev/null @@ -1,78 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -RSI: Relative Strength Index - Created by J. Welles Wilder, the Relative Strength Index measures strength - of the winning/losing streak over N lookback periods on a scale of 0 to 100, - to depict overbought and oversold conditions. - -Sources: - https://www.investopedia.com/terms/r/rsi.asp - - */ - -public class RSI_Series : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _gain = new(); - private readonly System.Collections.Generic.List _loss = new(); - private double _avgGain, _avgLoss, _lastValue; - private double _avgGain_o, _avgLoss_o, _lastValue_o; - private int i; - - public RSI_Series(TSeries source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) { - i = 0; - if (source.Count > 0) { base.Add(source); } - } - - public override void Add((System.DateTime t, double v) TValue, bool update) { - double _rsi = 0; - if (update) { - _lastValue = _lastValue_o; - _avgGain = _avgGain_o; - _avgLoss = _avgLoss_o; - } - else { - _lastValue_o = _lastValue; - _avgGain_o = _avgGain; - _avgLoss_o = _avgLoss; - } - - if (i == 0) { _lastValue = TValue.v; } - - double _gainval = (TValue.v > _lastValue) ? TValue.v - _lastValue : 0; - Add_Replace_Trim(_gain, _gainval, _p, update); - double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0; - Add_Replace_Trim(_loss, _lossval, _p, update); - _lastValue = TValue.v; - - // calculate RSI - if (i > _p) - { - _avgGain = ((_avgGain * (_p - 1)) + _gain[_gain.Count - 1]) / _p; - _avgLoss = ((_avgLoss * (_p - 1)) + _loss[_loss.Count - 1]) / _p; - if (_avgLoss > 0) { - double rs = _avgGain / _avgLoss; - _rsi = 100 - (100 / (1 + rs)); - } - else { _rsi = 100; } - } - // initialize average gain - else - { - double _sumGain = 0; - for (int p = 0; p < _gain.Count; p++) { _sumGain += _gain[p]; } - double _sumLoss = 0; - for (int p = 0; p < _loss.Count; p++) { _sumLoss += _loss[p]; } - - _avgGain = _sumGain / _gain.Count; - _avgLoss = _sumLoss / _loss.Count; - - _rsi = (_avgLoss > 0) ? 100 - (100 / (1 + (_avgGain / _avgLoss))) : 100; - } - - if (!update) { i++; } - var result = (TValue.t, (this.Count < this._p && this._NaN) ? double.NaN : _rsi); - base.Add(result, update); - } -} \ No newline at end of file diff --git a/Calculations/_Updated/ALMA_Series.cs b/Calculations/_Updated/ALMA_Series.cs new file mode 100644 index 00000000..18ba3339 --- /dev/null +++ b/Calculations/_Updated/ALMA_Series.cs @@ -0,0 +1,107 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Linq; + +/* +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/ + + Discrepancy with Pandas-TA (but passes the validation with Skender.GetAlma) + */ + +public class ALMA_Series : TSeries { + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + private readonly System.Collections.Generic.List _buffer = new(); + private readonly System.Collections.Generic.List _weight = new(); + private double _norm; + private readonly double _offset, _sigma; + + //core constructors + public ALMA_Series(int period, double offset, double sigma, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"ALMA({period})"; + _offset = offset; + _sigma = sigma; + _weight = new(); + } + public ALMA_Series(TSeries source, int period, double offset, double sigma, bool useNaN) : this(period, offset, sigma, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + + public ALMA_Series() : this(period:0, offset:0.85, sigma:6.0, useNaN: false) { } + public ALMA_Series(int period) : this(period: period, offset:0.85, sigma:6.0, useNaN:false) { } + public ALMA_Series(TBars source) : this(source:source.Close, period:0, offset:0.85, sigma:6.0, useNaN:false) { } + public ALMA_Series(TBars source, int period) : this(source:source.Close, period:period, offset: 0.85, sigma: 6.0, useNaN: false) { } + public ALMA_Series(TBars source, int period, double offset, double sigma, bool useNaN) : this(source.Close, period:period, offset: offset, sigma: sigma, useNaN: false) { } + public ALMA_Series(TSeries source) : this(source, period:0, offset:0.85, sigma:6.0, useNaN:false) { } + public ALMA_Series(TSeries source, int period) : this(source:source, period:period, offset:0.85, sigma:6.0, useNaN:false) { } + public ALMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, offset: 0.85, sigma: 6.0, useNaN: useNaN) { } + + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update=false) { + BufferTrim(_buffer, TValue.v, _period, update); + if (_weight.Count < _buffer.Count) { + for (int i = 0; i < (_buffer.Count - _weight.Count); i++) { _weight.Add(0.0); } + } + if (this._buffer.Count <= _period || _period ==0) { + 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; + } + } + + double _weightedSum = 0; + for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; } + double _alma = _weightedSum / _norm; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _alma); + return base.Add(res, update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + _weight.Clear(); + } + + //variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/BIAS_Series.cs b/Calculations/_Updated/BIAS_Series.cs new file mode 100644 index 00000000..8fa734d5 --- /dev/null +++ b/Calculations/_Updated/BIAS_Series.cs @@ -0,0 +1,75 @@ +namespace QuanTAlib; +using System; + +/* +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 + = (close / SMA) - 1 + +Sources: + https://en.wikipedia.org/wiki/Bias_of_an_estimator + + */ + +public class BIAS_Series : TSeries { + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private readonly SMA_Series _sma; + + //core constructors + public BIAS_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"BIAS({period})"; + _sma = new(period, false); + } + public BIAS_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public BIAS_Series() : this(period: 0, useNaN: false) { } + public BIAS_Series(int period) : this(period: period, useNaN: false) { } + public BIAS_Series(TBars source) : this(source.Close, 0, false) { } + public BIAS_Series(TBars source, int period) : this(source.Close, period, false) { } + public BIAS_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public BIAS_Series(TSeries source) : this(source, 0, false) { } + public BIAS_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + var _s = _sma.Add(TValue,update); + double _bias = (TValue.v / ((_s.v!=0)?_s.v:1)) - 1; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _bias); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _sma.Reset(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/CMO_Series.cs b/Calculations/_Updated/CMO_Series.cs new file mode 100644 index 00000000..6a7520b1 --- /dev/null +++ b/Calculations/_Updated/CMO_Series.cs @@ -0,0 +1,92 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +CMO: Chande Momentum Oscillator + Chande Momentum Oscillator (also known as CMO indicator) was developed by Tushar S. Chande + CMO is similar to other momentum oscillators (e.g. RSI or Stochastics). Alike RSI oscillator, + the CMO values move in the range from -100 to +100 points and its aim is to detect the + overbought and oversold market conditions. CMO calculates the price momentum on both the up + days as well as the down days. The CMO calculation is based on non-smoothed price values + meaning that it can reach its extremes more frequently and the short-time swings are more visible. + +Sources: + https://www.technicalindicators.net/indicators-technical-analysis/144-cmo-chande-momentum-oscillator + + */ + +public class CMO_Series : TSeries { + private readonly System.Collections.Generic.List _buff_up = new(); + private readonly System.Collections.Generic.List _buff_dn = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private double _plast_value, _last_value; + + //core constructors + public CMO_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"CMO({period})"; + } + public CMO_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public CMO_Series() : this(period: 0, useNaN: false) { } + public CMO_Series(int period) : this(period: period, useNaN: false) { } + public CMO_Series(TBars source) : this(source.Close, 0, false) { } + public CMO_Series(TBars source, int period) : this(source.Close, period, false) { } + public CMO_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public CMO_Series(TSeries source) : this(source, 0, false) { } + public CMO_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (update) { _last_value = _plast_value; } else { _plast_value = _last_value; } + BufferTrim(buffer:_buff_up, (TValue.v > _last_value) ? TValue.v - _last_value : 0, period:_period, update: update); + BufferTrim(buffer: _buff_dn, (TValue.v < _last_value) ? _last_value - TValue.v : 0, period: _period, update: update); + _last_value = TValue.v; + double _cmo_up = 0; + double _cmo_dn = 0; + for (int i = 0; i < Math.Min(_buff_up.Count, _buff_dn.Count); i++) { + _cmo_up += _buff_up[i]; + _cmo_dn += _buff_dn[i]; + } + double _cmo = 100 * (_cmo_up - _cmo_dn) / (_cmo_up + _cmo_dn); + if (_cmo_up + _cmo_dn == 0) { _cmo = 0; } + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _cmo); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buff_up.Clear(); + _buff_dn.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/CUSUM_Series.cs b/Calculations/_Updated/CUSUM_Series.cs new file mode 100644 index 00000000..333a1466 --- /dev/null +++ b/Calculations/_Updated/CUSUM_Series.cs @@ -0,0 +1,74 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +CUSUM: Cumulative Sum (aka Running Total) + SUM across a period provides a rolling sum of all values across the period. + If SUM values would be divided with period, the output would be SMA() + +Sources: + https://en.wikipedia.org/wiki/CUSUM + */ + +public class CUSUM_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public CUSUM_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"CUSUM({period})"; + } + public CUSUM_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public CUSUM_Series() : this(period: 0, useNaN: false) { } + public CUSUM_Series(int period) : this(period: period, useNaN: false) { } + public CUSUM_Series(TBars source) : this(source.Close, 0, false) { } + public CUSUM_Series(TBars source, int period) : this(source.Close, period, false) { } + public CUSUM_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public CUSUM_Series(TSeries source) : this(source, 0, false) { } + public CUSUM_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sum = 0; + for (int i = 0; i < _buffer.Count; i++) { _sum += _buffer[i]; } + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sum); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/DECAY_Series.cs b/Calculations/_Updated/DECAY_Series.cs new file mode 100644 index 00000000..194f639a --- /dev/null +++ b/Calculations/_Updated/DECAY_Series.cs @@ -0,0 +1,86 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +DECAY: + Linear decay can be modeled by a straight line with a negative slope of 1/period. + The value decreases in a straight line from the last maximum to 0. + Decay = Last Max - distance/period + + Exponential decay is modeled as an exponential curve with diminishing factor of + 1-1/p + + */ + +public class DECAY_Series : TSeries { + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private readonly bool _exp; + private double _pdecay, _ppdecay; + private readonly double _dfactor; + + //core constructors + public DECAY_Series(int period, bool exponential, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"DECAY({period})"; + _exp = exponential; + _dfactor = (_exp) ? 1.0 - 1.0 / (double)_period : 1 / (double)_period; + _pdecay = _ppdecay = 0; + } + public DECAY_Series(TSeries source, int period, bool exponential, bool useNaN) : this(period, exponential, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public DECAY_Series() : this(period: 0, exponential: false, useNaN: false) { } + public DECAY_Series(int period) : this(period: period, exponential: false, useNaN: false) { } + public DECAY_Series(TBars source) : this(source.Close, period: 0, exponential: false, useNaN: false) { } + public DECAY_Series(TBars source, int period) : this(source.Close, period: period, exponential:false, useNaN:false) { } + public DECAY_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, exponential: false, useNaN) { } + public DECAY_Series(TSeries source) : this(source, period: 0, exponential: false, useNaN:false) { } + public DECAY_Series(TSeries source, int period) : this(source: source, period: period, exponential: false, useNaN: false) { } + public DECAY_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, exponential: false, useNaN: useNaN) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN), update); + } + if (update) { _pdecay = _ppdecay; } + else { _ppdecay = _pdecay; } + + if (this.Count == 0) { _pdecay = TValue.v; } + double _decay = Math.Max(TValue.v, Math.Max((_exp) ? _pdecay * _dfactor : _pdecay - _dfactor, 0)); + _pdecay = _decay; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _decay); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _pdecay = _ppdecay = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/DEMA_Series.cs b/Calculations/_Updated/DEMA_Series.cs new file mode 100644 index 00000000..afec6a2c --- /dev/null +++ b/Calculations/_Updated/DEMA_Series.cs @@ -0,0 +1,131 @@ +namespace QuanTAlib; + +using System; +using System.Linq; + +/* +DEMA: Double 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/ + +Remark: + ema1 = EMA(close, length) + ema2 = EMA(ema1, length) + DEMA = 2 * ema1 - ema2 + + */ + +public class DEMA_Series : TSeries { + private double _k; + private double _sum, _oldsum; + private double _lastema1, _oldema1, _lastema2, _oldema2; + private int _len; + private readonly bool _useSMA; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + +//core constructor + public DEMA_Series(int period, bool useNaN, bool useSMA) : base() { + _period = period; + _NaN = useNaN; + _useSMA = useSMA; + Name = $"DEMA({period})"; + _k = 2.0 / (_period + 1); + _len = 0; + _sum = _oldsum = _lastema1 = _lastema2 = 0; + } + //generic constructors (source) + + public DEMA_Series() : this(0, false, true) {} + public DEMA_Series(int period) : this(period, false, true) {} + public DEMA_Series(TBars source) : this(source.Close, 0, false) {} + public DEMA_Series(TBars source, int period) : this(source.Close, period, false) {} + public DEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {} + public DEMA_Series(TSeries source, int period) : this(source, period, false, true) {} + public DEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {} + public DEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + +// core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (update) { + _lastema1 = _oldema1; + _lastema2 = _oldema2; + _sum = _oldsum; + } + else { + _oldema1 = _lastema1; + _oldema2 = _lastema2; + _oldsum = _sum; + _len++; + } + + if (_period == 0) { + _k = 2.0 / (_len + 1); + } + + double _ema1, _ema2, _dema; + if (Count == 0) { + _ema1 = _ema2 = _sum = TValue.v; + } + else if (_len <= _period && _useSMA && _period != 0) { + _sum += TValue.v; + _ema1 = _sum / Math.Min(_len, _period); + _ema2 = _ema1; + } + else { + _ema1 = (TValue.v - _lastema1) * _k + _lastema1; + _ema2 = (_ema1 - _lastema2) * _k + _lastema2; + } + + _dema = 2 * _ema1 - _ema2; + + _lastema1 = double.IsNaN(_ema1) ? _lastema1 : _ema1; + _lastema2 = double.IsNaN(_ema2) ? _lastema2 : _ema2; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _dema); + return base.Add(res, update); + } + +//variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { + return (DateTime.Today, double.NaN); + } + + foreach (var item in data) { + Add(item, false); + } + + return _data.Last; + } + + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + + public (DateTime t, double v) Add(bool update) { + return Add(_data.Last, update); + } + + public (DateTime t, double v) Add() { + return Add(_data.Last, false); + } + + private new void Sub(object source, TSeriesEventArgs e) { + Add(_data.Last, e.update); + } + + //reset calculation + public override void Reset() { + _sum = _oldsum = _lastema1 = _lastema2 = 0; + _len = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/DWMA_Series.cs b/Calculations/_Updated/DWMA_Series.cs new file mode 100644 index 00000000..91df946c --- /dev/null +++ b/Calculations/_Updated/DWMA_Series.cs @@ -0,0 +1,126 @@ +namespace QuanTAlib; + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +/* +DWMA: Double Weighted Moving Average + The weights are decreasing over the period with p^2 decay + and the most recent data has the heaviest weight. + + */ + +public class DWMA_Series : TSeries { + private readonly List _buffer = new(); + private List _weights = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + protected int _len; + +//core constructors + public DWMA_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"DWMA({period})"; + _len = 0; + _weights = CalculateWeights(_period); + } + + public DWMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + + public DWMA_Series() : this(0, false) { + } + + public DWMA_Series(int period) : this(period, false) { + } + + public DWMA_Series(TBars source) : this(source.Close, 0, false) { + } + + public DWMA_Series(TBars source, int period) : this(source.Close, period, false) { + } + + public DWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { + } + + public DWMA_Series(TSeries source, int period) : this(source, period, false) { + } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(_buffer, TValue.v, _period, update); + if (_period == 0) { + _len++; + _weights = CalculateWeights(_len); + } + + double _dwma = 0, _wsum = 0; + var bufferCount = _buffer.Count; + + var lockObj = new object(); + Parallel.For(0, bufferCount, i => + { + var temp = _buffer[i] * _weights[i]; + lock (lockObj) { + _dwma += temp; + _wsum += _weights[i]; + } + }); + _dwma /= _wsum; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _dwma); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { + return (DateTime.Today, double.NaN); + } + + foreach (var item in data) { + Add(item, false); + } + + return _data.Last; + } + + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + + public (DateTime t, double v) Add(bool update) { + return Add(_data.Last, update); + } + + public (DateTime t, double v) Add() { + return Add(_data.Last, false); + } + + private new void Sub(object source, TSeriesEventArgs e) { + Add(_data.Last, e.update); + } + + //calculating weights + private static List CalculateWeights(int period) { + var weights = new List(period); + for (var i = 0; i < period; i++) { + weights.Add((i + 1) * (i + 1)); + } + + return weights; + } + + //reset calculation + public override void Reset() { + _len = 0; + _buffer.Clear(); + _weights = CalculateWeights(_period); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/EMA_Series.cs b/Calculations/_Updated/EMA_Series.cs new file mode 100644 index 00000000..8136f7da --- /dev/null +++ b/Calculations/_Updated/EMA_Series.cs @@ -0,0 +1,123 @@ +namespace QuanTAlib; + +using System; +using System.Linq; + +/* +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) + +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. + + */ + +public class EMA_Series : TSeries { + private double _k; + private double _lastema, _oldema; + private double _sum, _oldsum; + private int _len; + private readonly bool _useSMA; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + +//core constructors + + public EMA_Series(int period, bool useNaN, bool useSMA) : base() { + _period = period; + _NaN = useNaN; + _useSMA = useSMA; + Name = $"EMA({period})"; + _k = 2.0 / (_period + 1); + _len = 0; + _sum = _oldsum = _lastema = _oldema = 0; + } + public EMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public EMA_Series() : this(0, false, true) {} + public EMA_Series(int period) : this(period, false, true) {} + public EMA_Series(TBars source) : this(source.Close, 0, false) {} + public EMA_Series(TBars source, int period) : this(source.Close, period, false) {} + public EMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {} + public EMA_Series(TSeries source, int period) : this(source, period, false, true) {} + public EMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {} + + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) { + if (update) { + _lastema = _oldema; + _sum = _oldsum; + } + else { + _oldema = _lastema; + _oldsum = _sum; + _len++; + } + + double _ema = 0; + if (_period == 0) { + _k = 2.0 / (_len + 1); + } + + if (Count == 0) { + _ema = _sum = TValue.v; + } + else if (_len <= _period && _useSMA && _period != 0) { + _sum += TValue.v; + if (_period != 0 && _len > _period) { + _sum -= _data[Count - _period - (update ? 1 : 0)].v; + } + + _ema = _sum / Math.Min(_len, _period); + } + else { + _ema = _k * (TValue.v - _lastema) + _lastema; + } + + _lastema = double.IsNaN(_ema) ? _lastema : _ema; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _ema); + return base.Add(res, update); + } + +//variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _sum = _oldsum = _lastema = _oldema = 0; + _len = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/ENTROPY_Series.cs b/Calculations/_Updated/ENTROPY_Series.cs new file mode 100644 index 00000000..4abd1239 --- /dev/null +++ b/Calculations/_Updated/ENTROPY_Series.cs @@ -0,0 +1,90 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Linq; + +/* +ENTROPY: + Introduced by Claude Shannon in 1948, entropy measures the unpredictability + of the data, or equivalently, of its average information. + +Calculation: + P = close / Σ(close) + ENTROPY = Σ(-P * Log(P) / Log(base)) + +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 + + */ + +public class ENTROPY_Series : TSeries { + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private readonly double _logbase; + private readonly System.Collections.Generic.List _buffer = new(); + private readonly System.Collections.Generic.List _buff2 = new(); + + //core constructors + public ENTROPY_Series(int period, double logbase, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + _logbase = logbase; + Name = $"ENTROPY({period})"; + } + public ENTROPY_Series(TSeries source, int period, double logbase, bool useNaN) : this(period, logbase, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public ENTROPY_Series() : this(period: 0, logbase: 2.0, useNaN: false) { } + public ENTROPY_Series(int period) : this(period: period, logbase: 2.0, useNaN: false) { } + public ENTROPY_Series(TBars source) : this(source.Close, period: 0, logbase: 2.0, useNaN: false) { } + public ENTROPY_Series(TBars source, int period) : this(source.Close, period, logbase: 2.0, useNaN: false) { } + public ENTROPY_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, logbase: 2.0, useNaN: useNaN) { } + public ENTROPY_Series(TSeries source) : this(source, period: 0, logbase: 2.0, useNaN: false) { } + public ENTROPY_Series(TSeries source, int period) : this(source: source, period: period, logbase: 2.0, useNaN: false) { } + public ENTROPY_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, logbase: 2.0, useNaN: useNaN) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN), update); + } + BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update); + double _sum = _buffer.Sum(); + double _pp = this._buffer[^1] / _sum; + double _ppp = -_pp * Math.Log(_pp) / Math.Log(this._logbase); + BufferTrim(_buff2, _ppp, _period, update); + double _entp = _buff2.Sum(); + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _entp); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + _buff2.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/FWMA_Series.cs b/Calculations/_Updated/FWMA_Series.cs new file mode 100644 index 00000000..fb50117c --- /dev/null +++ b/Calculations/_Updated/FWMA_Series.cs @@ -0,0 +1,100 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Numerics; +using System.Linq; + +/* +FWMA: Fibonacci's Weighted Moving Average is similar to a Weighted Moving Average + (WMA) where the weights are based on the Fibonacci Sequence. + + */ +public class FWMA_Series : TSeries { + private readonly List _buffer = new(); + private List _weights = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + protected int _len; + + public FWMA_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"FWMA({period})"; + _len = 0; + _weights = CalculateWeights(_period); + } + + public FWMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + + public FWMA_Series() : this(period: 0, useNaN: false) { } + public FWMA_Series(int period) : this(period: period, useNaN: false) { } + public FWMA_Series(TBars source) : this(source.Close, 0, false) { } + public FWMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public FWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public FWMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update); + if (_period == 0) { + _len++; + _weights = CalculateWeights(_len); + } + double _fwma = 0; + double totalWeights = _weights.Sum(); + object lockObj = new object(); + Parallel.For(0, _buffer.Count, i => + { + double temp = _buffer[i] * _weights[i]; + lock (lockObj) { _fwma += temp; } + }); + _fwma /= totalWeights; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _fwma); + return base.Add(res, update); + } + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + private static List CalculateWeights(int period) { + //to prevent overflow, max period can be no more than 1476 + period = (period > 1476) ? 1476 : period; + List weights = new List(period); + BigInteger a = 0; + BigInteger b = 1; + for (int i = 0; i < period; i++) { + BigInteger temp = a; + a = b; + b = temp + b; + weights.Add((double)Decimal.Parse(a.ToString())); + } + return weights; + } + + public override void Reset() { + _weights = CalculateWeights(_period); + _buffer.Clear(); + } +} diff --git a/Calculations/_Updated/HEMA_Series.cs b/Calculations/_Updated/HEMA_Series.cs new file mode 100644 index 00000000..84d292bf --- /dev/null +++ b/Calculations/_Updated/HEMA_Series.cs @@ -0,0 +1,116 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +HEMA: Hull-EMA Moving Average - a hybrid indicator + Modified HUll Moving Average; instead of using WMA (Weighted MA) for calculation, + 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 : TSeries { + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private double _k1, _k2, _k3; + private int _len; + private double _lastema1, _oldema1; + private double _lastema2, _oldema2; + private double _lasthema, _oldhema; + + //core constructors + public HEMA_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"HEMA({period})"; + CalculateK(_period, out _k1, out _k2, out _k3); + _len = 0; + _lastema1 = _oldema1 = _lastema2 = _oldema2 = _lasthema = _oldhema = 0; + } + public HEMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public HEMA_Series() : this(period: 0, useNaN: false) { } + public HEMA_Series(int period) : this(period: period, useNaN: false) { } + public HEMA_Series(TBars source) : this(source.Close, 0, false) { } + public HEMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public HEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public HEMA_Series(TSeries source) : this(source, 0, false) { } + public HEMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (update) { + _lastema1 = _oldema1; + _lastema2 = _oldema2; + _lasthema = _oldhema; + } + else { + _oldema1 = _lastema1; + _oldema2 = _lastema2; + _oldhema = _lasthema; + } + double _ema1, _ema2, _hema; + if (_period == 0) { + _len++; + CalculateK(_len, out _k1, out _k2, out _k3); + } + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, double.NaN), update); + } else if (this.Count == 0) { + _ema1 = _ema2 = _hema = TValue.v; + } + else { + _ema1 = _k1 * (TValue.v - _lastema1) + _lastema1; + _ema2 = _k2 * (TValue.v - _lastema2) + _lastema2; + _hema = _k3 * (((2 * _ema1) - _ema2) - _lasthema) + _lasthema; + } + + _lastema1 = _ema1; + _lastema2 = _ema2; + _lasthema = _hema; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hema); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _lastema1 = _lastema2 = _lasthema = 0; + _oldema1 = _oldema2 = _oldhema = 0; + _len = 0; + } + + public static void CalculateK(int len, out double k1, out double k2, out double k3) { + k1 = 8 / (double)(len + 7); + k2 = 3 / (double)(len + 2); + k3 = 2 / Math.Sqrt(len + 3); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/HMA_Series.cs b/Calculations/_Updated/HMA_Series.cs new file mode 100644 index 00000000..3631acf4 --- /dev/null +++ b/Calculations/_Updated/HMA_Series.cs @@ -0,0 +1,91 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +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. + +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 { + protected int _period, _period2, _psqrt; + protected readonly bool _NaN; + protected readonly TSeries _data; + protected WMA_Series _wma1, _wma2, _wma3; + + //core constructors + public HMA_Series(int period, bool useNaN) : base() { + _period = period; + _period2 = period /2; + _psqrt = (int)Math.Sqrt(period); + _NaN = useNaN; + _wma1 = new(Math.Max(_period2,1), false); + _wma2 = new(Math.Max(_period,1), false); + _wma3 = new(Math.Max(_psqrt,1), useNaN); + Name = $"HMA({period})"; + } + public HMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public HMA_Series() : this(period: 0, useNaN: false) { } + public HMA_Series(int period) : this(period: period, useNaN: false) { } + public HMA_Series(TBars source) : this(source.Close, 0, false) { } + public HMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public HMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public HMA_Series(TSeries source) : this(source, 0, false) { } + public HMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (_period == 0) { + _wma1.Len = this.Count / 2; + _wma2.Len = this.Count; + _wma1.Len = (int)Math.Sqrt(this.Count); + } + double _w1 = _wma1.Add(TValue, update).v; + double _w2 = _wma2.Add(TValue, update).v; + double _hma = _wma3.Add((2 * _w1) - _w2, update).v; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hma); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _wma1.Reset(); + _wma2.Reset(); + _wma3.Reset(); + } +} \ No newline at end of file diff --git a/Calculations/Trends/JMA_Series.cs b/Calculations/_Updated/JMA_Series.cs similarity index 54% rename from Calculations/Trends/JMA_Series.cs rename to Calculations/_Updated/JMA_Series.cs index f3d221a3..bfa9f445 100644 --- a/Calculations/Trends/JMA_Series.cs +++ b/Calculations/_Updated/JMA_Series.cs @@ -1,5 +1,6 @@ namespace QuanTAlib; using System; +using System.Collections.Generic; using System.Linq; /* @@ -18,38 +19,51 @@ Issues: 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 { + */ + +public class JMA_Series : TSeries { + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; private readonly System.Collections.Generic.List volty_short = new(); private readonly System.Collections.Generic.List vsum_buff = new(); private readonly double pr; - public TSeries mma1 { get; } - public TSeries mma2 { get; } - private double upperBand, lowerBand, vsum, Kv; private double prev_ma1, prev_det0, prev_det1, prev_vsum, prev_jma; private double p_upperBand, p_lowerBand, p_Kv, p_prev_ma1, p_prev_det0, p_prev_det1, p_prev_vsum, p_prev_jma; private readonly int _voltyS, _voltyL; - public JMA_Series(TSeries source, int period, double phase = 0.0, int vshort = 10, int vlong = 65, bool useNaN = false) : base(source, period, useNaN) { + //core constructors + public JMA_Series(int period, double phase, int vshort, int vlong, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"JMA({period})"; upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = 0.0; - - Kv = 0; - pr = (phase * 0.01) + 1.5; if (phase < -100) { pr = 0.5; } if (phase > 100) { pr = 2.5; } _voltyS = vshort; _voltyL = vlong; - mma1 = new(); - mma2 = new(); - - if (base._data.Count > 0) { base.Add(base._data); } } - public override void Add((System.DateTime t, double v) TValue, bool update) { - double del1 = 0.0, del2 = 0.0; + public JMA_Series(TSeries source, int period, double phase, int vshort, int vlong, bool useNaN) : this(period, phase, vshort, vlong, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public JMA_Series() : this(period: 0, phase: 0, vshort:10, vlong:65, useNaN: false) { } + public JMA_Series(int period) : this(period: period, phase: 0, vshort: 10, vlong: 65, useNaN: false) { } + public JMA_Series(TBars source) : this(source.Close, period:0, phase:0.0, vshort:10, vlong:65, useNaN:false) { } + public JMA_Series(TBars source, int period) : this(source.Close, period, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { } + public JMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, phase: 0.0, vshort: 10, vlong: 65, useNaN: useNaN) { } + public JMA_Series(TSeries source) : this(source, period:0, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { } + public JMA_Series(TSeries source, int period) : this(source: source, period: period, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { } + public JMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, phase: 0.0, vshort: 10, vlong: 65, useNaN: useNaN) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { if (this.Count == 0) { prev_ma1 = prev_jma = TValue.v; } if (update) { upperBand = p_upperBand; @@ -72,9 +86,13 @@ public class JMA_Series : Single_TSeries_Indicator { p_prev_jma = prev_jma; } + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, double.NaN),update); + } + // from Tvalue to volty - del1 = TValue.v - upperBand; - del2 = TValue.v - lowerBand; + double del1 = TValue.v - upperBand; + double del2 = TValue.v - lowerBand; upperBand = (del1 > 0) ? TValue.v : TValue.v - (Kv * del1); lowerBand = (del2 < 0) ? TValue.v : TValue.v - (Kv * del2); double volty = 0; @@ -96,7 +114,7 @@ public class JMA_Series : Single_TSeries_Indicator { /// from avolty to rolty double rvolty = (avolty != 0) ? volty / avolty : 0; - double len1 = (Math.Log(Math.Sqrt(_p)) / Math.Log(2.0)) + 2; + double len1 = (Math.Log(Math.Sqrt(_period)) / Math.Log(2.0)) + 2; if (len1 < 0) { len1 = 0; } double pow1 = Math.Max(len1 - 2.0, 0.5); @@ -105,23 +123,45 @@ public class JMA_Series : Single_TSeries_Indicator { //// from rvolty to second smoothing double pow2 = Math.Pow(rvolty, pow1); - double beta = 0.45 * (_p - 1) / (0.45 * (_p - 1) + 2); + double beta = 0.45 * (_period - 1) / (0.45 * (_period - 1) + 2); Kv = Math.Pow(beta, Math.Sqrt(pow2)); double alpha = Math.Pow(beta, pow2); double ma1 = (1 - alpha) * TValue.v + alpha * prev_ma1; prev_ma1 = ma1; - mma1.Add(ma1); double det0 = (1 - beta) * (TValue.v - ma1) + beta * prev_det0; prev_det0 = det0; double ma2 = ma1 + pr * det0; - mma2.Add(ma2); double det1 = ((1 - alpha) * (1 - alpha) * (ma2 - prev_jma)) + (alpha * alpha * prev_det1); prev_det1 = det1; double jma = prev_jma + det1; prev_jma = jma; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : jma); + return base.Add(res, update); + } - base.Add((TValue.t, jma), update, _NaN); + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = 0.0; } } \ No newline at end of file diff --git a/Calculations/_Updated/KAMA_Series.cs b/Calculations/_Updated/KAMA_Series.cs new file mode 100644 index 00000000..87200bef --- /dev/null +++ b/Calculations/_Updated/KAMA_Series.cs @@ -0,0 +1,114 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +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. + + KAMA[i] = KAMA[i-1] + SC * ( price - KAMA[i-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 : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + private double _lastkama, _lastlastkama; + private int _len; + private readonly double _scFast, _scSlow; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public KAMA_Series(int period, int fast, int slow, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + _len = 0; + _scFast = 2.0 / (((period < fast) ? period : fast) + 1); + _scSlow = 2.0 / (slow + 1); + _lastkama = _lastlastkama = 0; + Name = $"KAMA({period})"; + } + public KAMA_Series(TSeries source, int period, int fast, int slow, bool useNaN) : this(period, fast, slow, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public KAMA_Series() : this(period: 0, fast: 2, slow: 30, useNaN: false) { } + public KAMA_Series(int period) : this(period: period, fast: 2, slow: 30, useNaN: false) { } + public KAMA_Series(TBars source) : this(source.Close, period: 0, fast: 2, slow: 30, useNaN: false) { } + public KAMA_Series(TBars source, int period) : this(source.Close, period: period, fast: 2, slow: 30, useNaN: false) { } + public KAMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, fast: 2, slow: 30, useNaN: useNaN) { } + public KAMA_Series(TSeries source) : this(source, period: 0, fast: 2, slow: 30, useNaN: false) { } + public KAMA_Series(TSeries source, int period) : this(source: source, period: period, fast: 2, slow: 30, useNaN: false) { } + public KAMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, fast: 2, slow: 30, useNaN: useNaN) { } + public KAMA_Series(TSeries source, int period, int fast, int slow) : this(source: source, period: period, fast: fast, slow: slow, useNaN: false) { } + + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN), update); + } + + if (update) { _lastkama = _lastlastkama; } + else { _lastlastkama = _lastkama; } + BufferTrim(buffer: _buffer, value: TValue.v, period: _period + 1, update: update); + + double _kama = 0; + if (this.Count < _period) { _kama = TValue.v; } + else { + double _change = Math.Abs(_buffer[^1] - _buffer[(_buffer.Count > _period + 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))); + } + _len++; + _lastkama = _kama; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _kama); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + _len = 0; + _lastkama = _lastlastkama = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/KURTOSIS_Series.cs b/Calculations/_Updated/KURTOSIS_Series.cs new file mode 100644 index 00000000..6c1b48c6 --- /dev/null +++ b/Calculations/_Updated/KURTOSIS_Series.cs @@ -0,0 +1,99 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Linq; + +/* +KURTOSIS: 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. + + The normal curve is called Mesokurtic curve. If the curve of a distribution is + more outlier prone (or heavier-tailed) than a normal or mesokurtic curve then + it is referred to as a Leptokurtic curve. If a curve is less outlier prone (or + lighter-tailed) than a normal curve, it is called as a platykurtic curve. + +Calculation: + sum4 = Σ(close-SMA)^4 + sum2 = (Σ(close-SMA)^2)^2 + KURTOSIS = length * (sum4/sum2) + +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/ + + */ + +public class KURTOSIS_Series : TSeries { + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private readonly System.Collections.Generic.List _buffer = new(); + + //core constructors + public KURTOSIS_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"KURTOSIS({period})"; + } + public KURTOSIS_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public KURTOSIS_Series() : this(period: 0, useNaN: false) { } + public KURTOSIS_Series(int period) : this(period: period, useNaN: false) { } + public KURTOSIS_Series(TSeries source) : this(source, period: 0, useNaN: false) { } + public KURTOSIS_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN), update); + } + + BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update); + double _n = _buffer.Count; + double _avg = _buffer.Average(); + + double _s2 = 0; + double _s4 = 0; + for (int i = 0; i < this._buffer.Count; i++) { + _s2 += (_buffer[i] - _avg) * (_buffer[i] - _avg); + _s4 += (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg); + } + + double _Vx = _s2 / (_n - 1); + double _kurt = (_n > 3) ? + (_n * (_n + 1) * _s4) / (_Vx * _Vx * (_n - 3) * (_n - 1) * (_n - 2)) - (3 * (_n - 1) * (_n - 1) / ((_n - 2) * (_n - 3))) //using Sheskin Algo + : (_s2 * _s2) / _n - 3; //using Snedecor and Cochran (1967) algo + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _kurt); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/MAD_Series.cs b/Calculations/_Updated/MAD_Series.cs new file mode 100644 index 00000000..e1f358cd --- /dev/null +++ b/Calculations/_Updated/MAD_Series.cs @@ -0,0 +1,82 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +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 + +Sources: + https://en.wikipedia.org/wiki/Average_absolute_deviation + + */ + +public class MAD_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public MAD_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"MAD({period})"; + } + public MAD_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public MAD_Series() : this(period: 0, useNaN: false) { } + public MAD_Series(int period) : this(period: period, useNaN: false) { } + public MAD_Series(TBars source) : this(source.Close, 0, false) { } + public MAD_Series(TBars source, int period) : this(source.Close, period, false) { } + public MAD_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public MAD_Series(TSeries source) : this(source, 0, false) { } + public MAD_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + double _mad = 0; + for (int i = 0; i < _buffer.Count; i++) { _mad += Math.Abs(_buffer[i] - _sma); } + _mad /= this._buffer.Count; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mad); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/MAPE_Series.cs b/Calculations/_Updated/MAPE_Series.cs new file mode 100644 index 00000000..776a9a12 --- /dev/null +++ b/Calculations/_Updated/MAPE_Series.cs @@ -0,0 +1,88 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +MAPE: Mean Absolute Percentage Error + Measures the size of the error in percentage terms + +Calculation: + MAPE = Σ(|close – SMA| / |close|) / n + +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 + + */ + +public class MAPE_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public MAPE_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"MAPE({period})"; + } + public MAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public MAPE_Series() : this(period: 0, useNaN: false) { } + public MAPE_Series(int period) : this(period: period, useNaN: false) { } + public MAPE_Series(TBars source) : this(source.Close, 0, false) { } + public MAPE_Series(TBars source, int period) : this(source.Close, period, false) { } + public MAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public MAPE_Series(TSeries source) : this(source, 0, false) { } + public MAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + double _mape = 0; + for (int i = 0; i < _buffer.Count; i++) { + _mape += (_buffer[i] != 0) ? Math.Abs(_buffer[i] - _sma) / Math.Abs(_buffer[i]) : double.PositiveInfinity; + } + _mape /= (_buffer.Count > 0) ? _buffer.Count : 1; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mape); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/MAX_Series.cs b/Calculations/_Updated/MAX_Series.cs new file mode 100644 index 00000000..0eae2b6f --- /dev/null +++ b/Calculations/_Updated/MAX_Series.cs @@ -0,0 +1,71 @@ +using System.Linq; + +namespace QuanTAlib; +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 : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public MAX_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"MAX({period})"; + } + public MAX_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public MAX_Series() : this(period: 0, useNaN: false) { } + public MAX_Series(int period) : this(period: period, useNaN: false) { } + public MAX_Series(TBars source) : this(source.Close, 0, false) { } + public MAX_Series(TBars source, int period) : this(source.Close, period, false) { } + public MAX_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public MAX_Series(TSeries source) : this(source, 0, false) { } + public MAX_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _max= _buffer.Max(); + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _max); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/MEDIAN_Series.cs b/Calculations/_Updated/MEDIAN_Series.cs new file mode 100644 index 00000000..18e46c67 --- /dev/null +++ b/Calculations/_Updated/MEDIAN_Series.cs @@ -0,0 +1,89 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +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. + + 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 + +Sources: + https://corporatefinanceinstitute.com/resources/knowledge/other/median/ + https://en.wikipedia.org/wiki/Median + + */ + +public class MEDIAN_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public MEDIAN_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"MEDIAN({period})"; + } + public MEDIAN_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public MEDIAN_Series() : this(period: 0, useNaN: false) { } + public MEDIAN_Series(int period) : this(period: period, useNaN: false) { } + public MEDIAN_Series(TBars source) : this(source.Close, 0, false) { } + public MEDIAN_Series(TBars source, int period) : this(source.Close, period, false) { } + public MEDIAN_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public MEDIAN_Series(TSeries source) : this(source, 0, false) { } + public MEDIAN_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + System.Collections.Generic.List _s = new(this._buffer); + _s.Sort(); + int _p1 = _s.Count / 2; + int _p2 = Math.Max(0, (_s.Count / 2) - 1); + double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _med); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/MIDPOINT_Series.cs b/Calculations/_Updated/MIDPOINT_Series.cs new file mode 100644 index 00000000..686f9825 --- /dev/null +++ b/Calculations/_Updated/MIDPOINT_Series.cs @@ -0,0 +1,75 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +MIDPOINT: Midpoint value (max+min)/2 in the given period in the series. + If period = 0 => period = full length of the series + +Sources: + https://thefaqblog.com/what-is-the-midpoint-in-statistics/ + + */ + +public class MIDPOINT_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public MIDPOINT_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"MIDPOINT({period})"; + } + public MIDPOINT_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public MIDPOINT_Series() : this(period: 0, useNaN: false) { } + public MIDPOINT_Series(int period) : this(period: period, useNaN: false) { } + public MIDPOINT_Series(TBars source) : this(source.Close, 0, false) { } + public MIDPOINT_Series(TBars source, int period) : this(source.Close, period, false) { } + public MIDPOINT_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public MIDPOINT_Series(TSeries source) : this(source, 0, false) { } + public MIDPOINT_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _max= _buffer.Max(); + double _min = _buffer.Min(); + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : (_max+_min)*0.5); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/MIN_Series.cs b/Calculations/_Updated/MIN_Series.cs new file mode 100644 index 00000000..30b68fae --- /dev/null +++ b/Calculations/_Updated/MIN_Series.cs @@ -0,0 +1,71 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +MIN - Minimum value in the given period in the series. + If period = 0 => period = full length of the series + + */ + +public class MIN_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public MIN_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"MAX({period})"; + } + public MIN_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public MIN_Series() : this(period: 0, useNaN: false) { } + public MIN_Series(int period) : this(period: period, useNaN: false) { } + public MIN_Series(TBars source) : this(source.Close, 0, false) { } + public MIN_Series(TBars source, int period) : this(source.Close, period, false) { } + public MIN_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public MIN_Series(TSeries source) : this(source, 0, false) { } + public MIN_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _max= _buffer.Min(); + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _max); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/MSE_Series.cs b/Calculations/_Updated/MSE_Series.cs new file mode 100644 index 00000000..18406554 --- /dev/null +++ b/Calculations/_Updated/MSE_Series.cs @@ -0,0 +1,79 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +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 + + */ + +public class MSE_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public MSE_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"MSE({period})"; + } + public MSE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public MSE_Series() : this(period: 0, useNaN: false) { } + public MSE_Series(int period) : this(period: period, useNaN: false) { } + public MSE_Series(TBars source) : this(source.Close, 0, false) { } + public MSE_Series(TBars source, int period) : this(source.Close, period, false) { } + public MSE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public MSE_Series(TSeries source) : this(source, 0, false) { } + public MSE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + double _mse = 0; + for (int i = 0; i < _buffer.Count; i++) { _mse += (_buffer[i] - _sma) * (_buffer[i] - _sma); } + _mse /= this._buffer.Count; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mse); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/RMA_Series.cs b/Calculations/_Updated/RMA_Series.cs new file mode 100644 index 00000000..b5be9d9c --- /dev/null +++ b/Calculations/_Updated/RMA_Series.cs @@ -0,0 +1,119 @@ +namespace QuanTAlib; + +using System; +using System.Linq; + +/* +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. + +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 + +Issues: + Pandas-TA library calculates RMA using straight Exponential Weighted Mean: + pandas.ewm().mean() and returns incorrect first (period) of bars compared to + published formula. This implementation passess the validation test in Wilder's book. + + */ + +public class RMA_Series : TSeries { + private double _k; + private double _lastrma, _oldrma; + private double _sum, _oldsum; + private readonly bool _useSMA; + private int _len; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + +//core constructor + public RMA_Series(int period, bool useNaN, bool useSMA) : base() { + _period = period; + _NaN = useNaN; + _useSMA = useSMA; + Name = $"RMA({period})"; + _k = 1.0 / (double)(this._period); + _len = 0; + _sum = _oldsum = _lastrma = _oldrma = 0; + } + //generic constructors (source) + + public RMA_Series() : this(0, false, true) {} + public RMA_Series(int period) : this(period, false, true) {} + public RMA_Series(TBars source) : this(source.Close, 0, false) {} + public RMA_Series(TBars source, int period) : this(source.Close, period, false) {} + public RMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {} + public RMA_Series(TSeries source, int period) : this(source, period, false, true) {} + public RMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {} + public RMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + +// core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) { + if (update) { + _lastrma = _oldrma; + _sum = _oldsum; + } + else { + _oldrma = _lastrma; + _oldsum = _sum; + _len++; + } + + double _rma = 0; + if (_period == 0) { + _k = 1.0 / (double)(this._len); + } + + if (Count == 0) { + _rma = _sum = TValue.v; + + } else if (_len <= _period && _useSMA && _period != 0) { + _sum += TValue.v; + if (_period != 0 && _len > _period) { + _sum -= _data[Count - _period - (update ? 1 : 0)].v; + } + _rma = _sum / Math.Min(_len, _period); + } + else { + _rma = _k * (TValue.v - _lastrma) + _lastrma; + } + + _lastrma = double.IsNaN(_rma) ? _lastrma : _rma; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _rma); + return base.Add(res, update); + } + +//variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _sum = _oldsum = _lastrma = _oldrma = 0; + _len = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/RSI_Series.cs b/Calculations/_Updated/RSI_Series.cs new file mode 100644 index 00000000..a1cd561e --- /dev/null +++ b/Calculations/_Updated/RSI_Series.cs @@ -0,0 +1,123 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +RSI: Relative Strength Index + Created by J. Welles Wilder, the Relative Strength Index measures strength + of the winning/losing streak over N lookback periods on a scale of 0 to 100, + to depict overbought and oversold conditions. + +Sources: + https://www.investopedia.com/terms/r/rsi.asp + + */ + +public class RSI_Series : TSeries { + private readonly System.Collections.Generic.List _gain = new(); + private readonly System.Collections.Generic.List _loss = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private double _avgGain, _avgLoss, _lastValue; + private double _avgGain_o, _avgLoss_o, _lastValue_o; + private int i; + + //core constructors + public RSI_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"RSI({period})"; + i = 0; + } + public RSI_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public RSI_Series() : this(period: 0, useNaN: false) { } + public RSI_Series(int period) : this(period: period, useNaN: false) { } + public RSI_Series(TBars source) : this(source.Close, 0, false) { } + public RSI_Series(TBars source, int period) : this(source.Close, period, false) { } + public RSI_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public RSI_Series(TSeries source) : this(source, 0, false) { } + public RSI_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + + double _rsi = 0; + if (update) { + _lastValue = _lastValue_o; + _avgGain = _avgGain_o; + _avgLoss = _avgLoss_o; + } + else { + _lastValue_o = _lastValue; + _avgGain_o = _avgGain; + _avgLoss_o = _avgLoss; + } + + if (i == 0) { _lastValue = TValue.v; } + + double _gainval = (TValue.v > _lastValue) ? TValue.v - _lastValue : 0; + BufferTrim(_gain, _gainval, _period, update); + double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0; + BufferTrim(_loss, _lossval, _period, update); + _lastValue = TValue.v; + + // calculate RSI + if (i > _period && _period != 0) { + _avgGain = ((_avgGain * (_period - 1)) + _gain[^1]) / _period; + _avgLoss = ((_avgLoss * (_period - 1)) + _loss[^1]) / _period; + if (_avgLoss > 0) { + double rs = _avgGain / _avgLoss; + _rsi = 100 - (100 / (1 + rs)); + } + else { _rsi = 100; } + } + // initialize average gain + else { + double _sumGain = 0; + for (int p = 0; p < _gain.Count; p++) { _sumGain += _gain[p]; } + double _sumLoss = 0; + for (int p = 0; p < _loss.Count; p++) { _sumLoss += _loss[p]; } + + _avgGain = _sumGain / _gain.Count; + _avgLoss = _sumLoss / _loss.Count; + + _rsi = (_avgLoss > 0) ? 100 - (100 / (1 + (_avgGain / _avgLoss))) : 100; + } + if (!update) { i++; } + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _rsi); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + i = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/SDEV_Series.cs b/Calculations/_Updated/SDEV_Series.cs new file mode 100644 index 00000000..90d269cd --- /dev/null +++ b/Calculations/_Updated/SDEV_Series.cs @@ -0,0 +1,85 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +SDEV: 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 + +Remark: + SDEV (Population Standard Deviation) is also known as a biased/uncorrected Standard Deviation. + For unbiased version that uses Bessel's correction, use SDEV instead. + + */ + +public class SDEV_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public SDEV_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"SDEV({period})"; + } + public SDEV_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public SDEV_Series() : this(period: 0, useNaN: false) { } + public SDEV_Series(int period) : this(period: period, useNaN: false) { } + public SDEV_Series(TBars source) : this(source.Close, 0, false) { } + public SDEV_Series(TBars source, int period) : this(source.Close, period, false) { } + public SDEV_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public SDEV_Series(TSeries source) : this(source, 0, false) { } + public SDEV_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + double _var = 0; + for (int i = 0; i < _buffer.Count; i++) { _var += (_buffer[i] - _sma) * (_buffer[i] - _sma); } + _var /= this._buffer.Count; + double _sdev = Math.Sqrt(_var); + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sdev); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/SMAPE_Series.cs b/Calculations/_Updated/SMAPE_Series.cs new file mode 100644 index 00000000..7ab08d6a --- /dev/null +++ b/Calculations/_Updated/SMAPE_Series.cs @@ -0,0 +1,80 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +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 + + */ + +public class SMAPE_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public SMAPE_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"SMAPE({period})"; + } + public SMAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public SMAPE_Series() : this(period: 0, useNaN: false) { } + public SMAPE_Series(int period) : this(period: period, useNaN: false) { } + public SMAPE_Series(TBars source) : this(source.Close, 0, false) { } + public SMAPE_Series(TBars source, int period) : this(source.Close, period, false) { } + public SMAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public SMAPE_Series(TSeries source) : this(source, 0, false) { } + public SMAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + + double _smape = 0; + for (int i = 0; i < _buffer.Count; i++) { _smape += Math.Abs(_buffer[i] - _sma) / (Math.Abs(_buffer[i]) + Math.Abs(_sma)); } + _smape /= this._buffer.Count; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _smape); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/SMA_Series.cs b/Calculations/_Updated/SMA_Series.cs new file mode 100644 index 00000000..30ccc4ba --- /dev/null +++ b/Calculations/_Updated/SMA_Series.cs @@ -0,0 +1,99 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +SMA: Simple Moving Average + 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 (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 : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + + private double _sum, _oldsum; + private readonly int _period; + private readonly TSeries _data; + protected readonly bool _NaN; + + //core constructor + public SMA_Series(int period, bool useNaN) : base() { + _period = Math.Max(0, period); + _NaN = useNaN; + Name = $"SMA({period})"; + _sum = _oldsum = 0; + } + public SMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public SMA_Series() : this(0, false) {} + public SMA_Series(int period) : this(period, false) {} + public SMA_Series(TBars source) : this(source.Close, 0, false) {} + public SMA_Series(TBars source, int period) : this(source.Close, period, false) {} + public SMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {} + public SMA_Series(TSeries source) : this(source, 0, false) {} + public SMA_Series(TSeries source, int period) : this(source, period, false) {} + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) { + if (double.IsNaN(TValue.v)) { return (TValue.t, double.NaN); + } else { + if (update && _buffer.Count > 0) { + _sum -= _buffer[^1]; + _buffer[^1] = TValue.v; + _oldsum = _sum; + } + else { + _buffer.Add(TValue.v); + _oldsum = _sum; + } + + _sum += TValue.v; + if (_period != 0 && _buffer.Count > _period) { + _sum -= _buffer[0]; + _buffer.RemoveAt(0); + } + } + + double _div = _period == 0 ? _buffer.Count : Math.Min(_buffer.Count, _period); + var _sma = _sum / _div; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sma); + return base.Add(res, update); + } + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + + //reset calculation + public override void Reset() { + _sum = _oldsum = 0; + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/SMMA_Series.cs b/Calculations/_Updated/SMMA_Series.cs new file mode 100644 index 00000000..50bed0ba --- /dev/null +++ b/Calculations/_Updated/SMMA_Series.cs @@ -0,0 +1,96 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Linq; + +/* +SMMA: Smoothed Moving Average + The Smoothed Moving Average (SMMA) is a combination of a SMA and an EMA. It gives the recent prices + an equal weighting as the historic prices as it takes all available price data into account. + The main advantage of a smoothed moving average is that it removes short-term fluctuations. + + SMMA(i) = (SMMA-1*(N-1) + CLOSE (i)) / N + +Sources: + https://blog.earn2trade.com/smoothed-moving-average + https://guide.traderevolution.com/traderevolution/mobile-applications/phone/android/technical-indicators/moving-averages/smma-smoothed-moving-average + https://www.chartmill.com/documentation/technical-analysis-indicators/217-MOVING-AVERAGES-%7C-The-Smoothed-Moving-Average-%28SMMA%29 + + */ + +public class SMMA_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private double _lastsmma, _lastlastsmma; + + //core constructors + public SMMA_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"SMMA({period})"; + } + public SMMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public SMMA_Series() : this(period: 0, useNaN: false) { } + public SMMA_Series(int period) : this(period: period, useNaN: false) { } + public SMMA_Series(TBars source) : this(source.Close, 0, false) { } + public SMMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public SMMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public SMMA_Series(TSeries source) : this(source, 0, false) { } + public SMMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, double.NaN),update); + } + + double _smma = 0; + if (update) { this._lastsmma = this._lastlastsmma; } + + if (this.Count < this._period) { + BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update); + _smma = _buffer.Average(); + } + else { + _smma = ((_lastsmma * (_period - 1)) + TValue.v) / _period; + } + + this._lastlastsmma = this._lastsmma; + this._lastsmma = _smma; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _smma); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + this._lastsmma = this._lastlastsmma = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/SSDEV_Series.cs b/Calculations/_Updated/SSDEV_Series.cs new file mode 100644 index 00000000..e295199a --- /dev/null +++ b/Calculations/_Updated/SSDEV_Series.cs @@ -0,0 +1,85 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +SSDEV: (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 + + */ + +public class SSDEV_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public SSDEV_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"SSDEV({period})"; + } + public SSDEV_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public SSDEV_Series() : this(period: 0, useNaN: false) { } + public SSDEV_Series(int period) : this(period: period, useNaN: false) { } + public SSDEV_Series(TBars source) : this(source.Close, 0, false) { } + public SSDEV_Series(TBars source, int period) : this(source.Close, period, false) { } + public SSDEV_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public SSDEV_Series(TSeries source) : this(source, 0, false) { } + public SSDEV_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + double _svar = 0; + for (int i = 0; i < this._buffer.Count; i++) { _svar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } + _svar /= (_buffer.Count > 1) ? _buffer.Count - 1 : 1; // Bessel's correction + double _ssdev = Math.Sqrt(_svar); + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _ssdev); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/SVAR_Series.cs b/Calculations/_Updated/SVAR_Series.cs new file mode 100644 index 00000000..4c4e0c8a --- /dev/null +++ b/Calculations/_Updated/SVAR_Series.cs @@ -0,0 +1,84 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +VAR: Population Variance + Population variance without Bessel's correction + +Sources: + https://en.wikipedia.org/wiki/Variance + Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction + +Remark: + VAR (Population Variance) is also known as a biased Sample Variance. For unbiased + sample variance use SVAR instead. + + */ + +public class SVAR_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public SVAR_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"SVAR({period})"; + } + public SVAR_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public SVAR_Series() : this(period: 0, useNaN: false) { } + public SVAR_Series(int period) : this(period: period, useNaN: false) { } + public SVAR_Series(TBars source) : this(source.Close, 0, false) { } + public SVAR_Series(TBars source, int period) : this(source.Close, period, false) { } + public SVAR_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public SVAR_Series(TSeries source) : this(source, 0, false) { } + public SVAR_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + double _svar = 0; + for (int i = 0; i < this._buffer.Count; i++) { _svar += (this._buffer[i] - _sma) * (this._buffer[i] - _sma); } + _svar /= (this._buffer.Count > 1) ? this._buffer.Count - 1 : 1; // Bessel's correction + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _svar); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/T3_Series.cs b/Calculations/_Updated/T3_Series.cs new file mode 100644 index 00000000..d9abbb65 --- /dev/null +++ b/Calculations/_Updated/T3_Series.cs @@ -0,0 +1,164 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Numerics; + +/* +T3: Tillson T3 Moving Average + Tim Tillson described it in "Technical Analysis of Stocks and Commodities", January 1998 in the + article "Better Moving Averages". Tillson’s moving average becomes a popular indicator of + technical analysis as it gets less lag with the price chart and its curve is considerably smoother. + +Sources: + https://technicalindicators.net/indicators-technical-analysis/150-t3-moving-average + http://www.binarytribune.com/forex-trading-indicators/t3-moving-average-indicator/ + */ + +public class T3_Series : TSeries { + private readonly double _k, _k1m, _c1, _c2, _c3, _c4; + private readonly System.Collections.Generic.List _buffer1 = new(); + private readonly System.Collections.Generic.List _buffer2 = new(); + private readonly System.Collections.Generic.List _buffer3 = new(); + private readonly System.Collections.Generic.List _buffer4 = new(); + private readonly System.Collections.Generic.List _buffer5 = new(); + private readonly System.Collections.Generic.List _buffer6 = new(); + private readonly bool _useSMA; + private double _lastema1, _lastema2, _lastema3, _lastema4, _lastema5, _lastema6; + private double _llastema1, _llastema2, _llastema3, _llastema4, _llastema5, _llastema6; + protected int _len; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public T3_Series(int period, double vfactor, bool useSMA, bool useNaN) : base() { + _period = period; + _len = 0; + _NaN = useNaN; + Name = $"T3({period})"; + _useSMA = useSMA; + double _a = vfactor; //0.7; //0.618 + _c1 = -_a * _a * _a; + _c2 = 3 * _a * _a + 3 * _a * _a * _a; + _c3 = -6 * _a * _a - 3 * _a - 3 * _a * _a * _a; + _c4 = 1 + 3 * _a + _a * _a * _a + 3 * _a * _a; + + _k = 2.0 / (_period + 1); + _k1m = 1.0 - _k; + _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = _lastema4 = _llastema4 = _lastema5 = _llastema5 = _lastema5 = _llastema5 = 0; + } + public T3_Series(TSeries source, int period, double vfactor, bool useSMA, bool useNaN) : this(period, vfactor, useSMA, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public T3_Series() : this(period: 0, vfactor: 0.7, useSMA: true, useNaN: false) { } + public T3_Series(int period) : this(period: period, vfactor: 0.7, useSMA: true, useNaN: false) { } + public T3_Series(TBars source) : this(source.Close, 0, vfactor: 0.7, useSMA: true, useNaN: false) { } + public T3_Series(TBars source, int period) : this(source.Close, period, vfactor: 0.7, useSMA: true, useNaN: false) { } + public T3_Series(TBars source, int period, bool useNaN) : this(source.Close, period, vfactor: 0.7, useSMA: true, useNaN: useNaN) { } + public T3_Series(TBars source, int period, double vfactor, bool useNaN) : this(source.Close, period, vfactor: vfactor, useSMA: true, useNaN: useNaN) { } + public T3_Series(TBars source, int period, bool useSMA, bool useNaN) : this(source.Close, period, vfactor: 0.7, useSMA: useSMA, useNaN: useNaN) { } + public T3_Series(TSeries source) : this(source, 0, vfactor: 0.7, useSMA: true, useNaN: false) { } + public T3_Series(TSeries source, int period) : this(source: source, period: period, vfactor: 0.7, useSMA: true, useNaN: false) { } + public T3_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, vfactor: 0.7, useSMA: true, useNaN: useNaN) { } + public T3_Series(TSeries source, int period, double vfactor) : this(source: source, period: period, vfactor: vfactor, useSMA: true, useNaN: false) { } + public T3_Series(TSeries source, int period, double vfactor, bool useNaN) : this(source: source, period: period, vfactor: vfactor, useSMA: true, useNaN: useNaN) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + double _ema1, _ema2, _ema3, _ema4, _ema5, _ema6; + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN),update); + } + + if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; _lastema4 = _llastema4; _lastema5 = _llastema5; _lastema6 = _llastema6; } + else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; _llastema4 = _lastema4; _llastema5 = _lastema5; _llastema6 = _lastema6; } + + if (_len == 0) { _lastema1 = _lastema2 = _lastema3 = _lastema4 = _lastema5 = _lastema6 = TValue.v; } + + + if ((_len < _period) && _useSMA) { + BufferTrim(_buffer1, TValue.v, _period, update); + _ema1 = 0; + for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; } + _ema1 /= _buffer1.Count; + + BufferTrim(_buffer2, _ema1, _period, update); + _ema2 = 0; + for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; } + _ema2 /= _buffer2.Count; + + BufferTrim(_buffer3, _ema2, _period, update); + _ema3 = 0; + for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; } + _ema3 /= _buffer3.Count; + + BufferTrim(_buffer4, _ema3, _period, update); + _ema4 = 0; + for (int i = 0; i < _buffer4.Count; i++) { _ema4 += _buffer4[i]; } + _ema4 /= _buffer4.Count; + + BufferTrim(_buffer5, _ema4, _period, update); + _ema5 = 0; + for (int i = 0; i < _buffer5.Count; i++) { _ema5 += _buffer5[i]; } + _ema5 /= _buffer5.Count; + + BufferTrim(_buffer6, _ema5, _period, update); + _ema6 = 0; + for (int i = 0; i < _buffer6.Count; i++) { _ema6 += _buffer6[i]; } + _ema6 /= _buffer6.Count; + } + 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); + _ema4 = (_ema3 * this._k) + (this._lastema4 * this._k1m); + _ema5 = (_ema4 * this._k) + (this._lastema5 * this._k1m); + _ema6 = (_ema5 * this._k) + (this._lastema6 * this._k1m); + } + _len++; + _lastema1 = _ema1; + _lastema2 = _ema2; + _lastema3 = _ema3; + _lastema4 = _ema4; + _lastema5 = _ema5; + _lastema6 = _ema6; + + double _T3 = _c1 * _ema6 + _c2 * _ema5 + _c3 * _ema4 + _c4 * _ema3; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _T3); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = _lastema4 = _llastema4 = _lastema5 = _llastema5 = _lastema5 = _llastema5 = 0; + _buffer1.Clear(); + _buffer2.Clear(); + _buffer3.Clear(); + _buffer4.Clear(); + _buffer5.Clear(); + _buffer6.Clear(); + _len = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/TBars.cs b/Calculations/_Updated/TBars.cs new file mode 100644 index 00000000..8387219d --- /dev/null +++ b/Calculations/_Updated/TBars.cs @@ -0,0 +1,126 @@ +namespace QuanTAlib; +using System; + +/* +TBars class - includes all series for common data used in indicators and other calculations. + Has a bit limited overloading and casting (compared to TSeries) + Includes Select(int) method to simplify choosing the most optimal data source for indicators + Includes the most basic pricing calcs: HL2, OC2, OHL3, HLC3, OHLC4, HLCC4 + (it is 'cheaper' to calculate them once during data capture than each time during data analysis) + + */ + +public class TBars : System.Collections.Generic.List<(DateTime t, double o, double h, double l, double c, double v)> +{ + public string Name { get; set; } + private readonly TSeries _open = new("open"); + private readonly TSeries _high = new("high"); + private readonly TSeries _low = new("low"); + private readonly TSeries _close = new("close"); + private readonly TSeries _volume = new("volume"); + private readonly TSeries _hl2 = new("HL2"); + private readonly TSeries _oc2 = new("OC2"); + private readonly TSeries _ohl3 = new("OHL3"); + private readonly TSeries _hlc3 = new("HLC3"); + private readonly TSeries _ohlc4 = new("OHLC4"); + private readonly TSeries _hlcc4 = new("HLCC4"); + + public TSeries Open => this._open; + public TSeries High => this._high; + public TSeries Low => this._low; + public TSeries Close => this._close; + public TSeries Volume => this._volume; + public TSeries HL2 => this._hl2; + public TSeries OC2 => this._oc2; + public TSeries OHL3 => this._ohl3; + public TSeries HLC3 => this._hlc3; + public TSeries OHLC4 => this._ohlc4; + public TSeries HLCC4 => this._hlcc4; + + public TBars() { } + + public TBars(string Name) { + this.Name = Name; + } + + public (DateTime t, double o, double h, double l, double c, double v) Last => this[^1]; + public TBars Tail(int count = 10) + { + TBars outBars = new(); + if (count > this.Count) { count = this.Count; } + for (int i = this.Count - count; i < this.Count; i++) { outBars.Add(this[i]); } + return outBars; + } + public TSeries Select(int source) + { + return source switch + { + 0 => _open, + 1 => _high, + 2 => _low, + 3 => _close, + 4 => _hl2, + 5 => _oc2, + 6 => _ohl3, + 7 => _hlc3, + 8 => _ohlc4, + _ => _hlcc4, + }; + } + public static string SelectStr(int source) + { + return source switch + { + 0 => "Open", + 1 => "High", + 2 => "Low", + 3 => "Close", + 4 => "HL2", + 5 => "OC2", + 6 => "OHL3", + 7 => "HLC3", + 8 => "OHLC4", + _ => "HLCC4", + }; + } + + public virtual (DateTime t, double o, double h, double l, double c, double v) Add((double o, double h, double l, double c, double v) p, bool update = false) => + Add((t: (this.Count == 0) ? DateTime.Today : this[^1].t.AddDays(1),p.o,p.h,p.l,p.c,p.v),update); + + public virtual (DateTime t, double o, double h, double l, double c, double v) Add(double o, double h, double l, double c, double v, bool update = false) => + Add((o,h,l,c,v),update); + + public virtual (DateTime t, double o, double h, double l, double c, double v) Add(DateTime t, double o, double h, double l, double c, double v, bool update = false) => + this.Add((t, o, h, l, c, v), update); + + public virtual (DateTime t, double o, double h, double l, double c, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) { + if (update) { this[^1] = TBar; } else { base.Add(TBar); } + + _open.Add((TBar.t, TBar.o), update); + _high.Add((TBar.t, TBar.h), update); + _low.Add((TBar.t, TBar.l), update); + _close.Add((TBar.t, TBar.c), update); + _volume.Add((TBar.t, TBar.v), update); + _hl2.Add((TBar.t, (TBar.h + TBar.l) * 0.5), update); + _oc2.Add((TBar.t, (TBar.o + TBar.c) * 0.5), update); + _ohl3.Add((TBar.t, (TBar.o + TBar.h + TBar.l) * 0.333333333333333), update); + _hlc3.Add((TBar.t, (TBar.h + TBar.l + TBar.c) * 0.333333333333333), update); + _ohlc4.Add((TBar.t, (TBar.o + TBar.h + TBar.l + TBar.c) * 0.25), update); + _hlcc4.Add((TBar.t, (TBar.h + TBar.l + TBar.c + TBar.c) * 0.25), update); + + this.OnEvent(update); + return TBar; + } + + public delegate void NewDataEventHandler(object source, TSeriesEventArgs args); + public event NewDataEventHandler Pub; + protected virtual void OnEvent(bool update = false) { if (Pub != null && Pub.Target != this) { + Pub(this, new TSeriesEventArgs { update = update }); } } + + public void Sub(object source, TSeriesEventArgs e) { TBars ss = (TBars)source; if (ss.Count > 1) { + for (int i = 0; i < ss.Count; i++) { this.Add(ss[i]); } + } else { + this.Add(ss[ss.Count - 1], e.update); + } + } +} diff --git a/Calculations/_Updated/TEMA_Series.cs b/Calculations/_Updated/TEMA_Series.cs new file mode 100644 index 00000000..b109995b --- /dev/null +++ b/Calculations/_Updated/TEMA_Series.cs @@ -0,0 +1,123 @@ +namespace QuanTAlib; + +using System; +using System.Linq; + +/* +TEMA: Triple 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/ + +Remark: + ema1 = EMA(close, length) + ema2 = EMA(ema1, length) + ema3 = EMA(ema2, length) + TEMA = 3 * (ema1 - ema2) + ema3 + + */ + +public class TEMA_Series : TSeries { + private double _k; + private double _sum, _oldsum; + private double _lastema1, _oldema1, _lastema2, _oldema2, _lastema3, _oldema3; + private int _len; + private readonly bool _useSMA; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + +//core constructor + public TEMA_Series(int period, bool useNaN, bool useSMA) : base() { + _period = period; + _NaN = useNaN; + _useSMA = useSMA; + Name = $"TEMA({period})"; + _k = 2.0 / (_period + 1); + _len = 0; + _sum = _oldsum = _lastema1 = _lastema2 = _lastema3 = 0; + } + public TEMA_Series() : this(0, false, true) {} + public TEMA_Series(int period) : this(period, false, true) {} + public TEMA_Series(TBars source) : this(source.Close, 0, false) {} + public TEMA_Series(TBars source, int period) : this(source.Close, period, false) {} + public TEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {} + public TEMA_Series(TSeries source, int period) : this(source, period, false, true) {} + public TEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {} + public TEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + +// core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (update) { + _lastema1 = _oldema1; + _lastema2 = _oldema2; + _lastema3 = _oldema3; + _sum = _oldsum; + } + else { + _oldema1 = _lastema1; + _oldema2 = _lastema2; + _oldema3 = _lastema3; + _oldsum = _sum; + _len++; + } + + if (_period == 0) { _k = 2.0 / (_len + 1); } + + double _ema1, _ema2, _ema3, _tema; + if (this.Count == 0) { + _ema1 = _ema2 = _ema3 =_sum = TValue.v; + } + else if (_len <= _period && _useSMA && _period != 0) { + _sum += TValue.v; + _ema1 = _sum / Math.Min(_len, _period); + _ema2 = _ema1; + _ema3 = _ema2; + } + else { + _ema1 = (TValue.v - _lastema1) * _k + _lastema1; + _ema2 = (_ema1 - _lastema2) * _k + _lastema2; + _ema3 = (_ema2 - _lastema3) * _k + _lastema3; + } + + _tema = (3 * (_ema1 - _ema2)) + _ema3; + + _lastema1 = Double.IsNaN(_ema1)?_lastema1:_ema1; + _lastema2 = Double.IsNaN(_ema2)?_lastema2:_ema2; + _lastema3 = Double.IsNaN(_ema3) ? _lastema3 : _ema3; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _tema); + return base.Add(res, update); + } + +//variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _sum = _oldsum = _lastema1 = _lastema2 = 0; + _len = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/TRIMA_Series.cs b/Calculations/_Updated/TRIMA_Series.cs new file mode 100644 index 00000000..70313693 --- /dev/null +++ b/Calculations/_Updated/TRIMA_Series.cs @@ -0,0 +1,87 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +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 : TSeries { + private readonly int _p1a, _p1b; + private SMA_Series sma, trima; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public TRIMA_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"xMA({period})"; + _p1a = (int)Math.Floor((period * 0.5) + 1); + _p1b = (int)Math.Ceiling(0.5 * period); + sma = new(_p1a); + trima = new(_p1b); + + } + public TRIMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public TRIMA_Series() : this(period: 0, useNaN: false) { } + public TRIMA_Series(int period) : this(period: period, useNaN: false) { } + public TRIMA_Series(TBars source) : this(source.Close, 0, false) { } + public TRIMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public TRIMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public TRIMA_Series(TSeries source) : this(source, 0, false) { } + public TRIMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN), update); + } + + var _sma = sma.Add(TValue, update); + var _trima = trima.Add(_sma, update); + + var res = (_trima.t, Count < _period - 1 && _NaN ? double.NaN : _trima.v); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + sma.Reset(); + trima.Reset(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/TRIX_Series.cs b/Calculations/_Updated/TRIX_Series.cs new file mode 100644 index 00000000..243dba19 --- /dev/null +++ b/Calculations/_Updated/TRIX_Series.cs @@ -0,0 +1,119 @@ +namespace QuanTAlib; + +using System; +using System.Linq; + +/* +TRIX: Triple Exponential Average Oscillator + Developed by Jack Hutson in the early 1980s, the triple exponential average (TRIX) + has become a popular technical analysis tool to aid chartists in spotting diversions + and directional cues in stock trading patterns. + +Sources: + https://www.investopedia.com/terms/t/trix.asp + + */ + +public class TRIX_Series : TSeries { + private readonly double _k; + private readonly System.Collections.Generic.List _buffer1 = new(); + private readonly System.Collections.Generic.List _buffer2 = new(); + private readonly System.Collections.Generic.List _buffer3 = new(); + private double _lastema1, _lastema2, _lastema3; + private double _llastema1, _llastema2, _llastema3; + + private readonly bool _useSMA; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + +//core constructors + + public TRIX_Series(int period, bool useNaN, bool useSMA) : base() { + _period = period; + _NaN = useNaN; + _useSMA = useSMA; + Name = $"TRIX({period})"; + _k = 2.0 / (_period + 1); + _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = 0; + } + public TRIX_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public TRIX_Series() : this(0, false, true) {} + public TRIX_Series(int period) : this(period, false, true) {} + public TRIX_Series(TBars source) : this(source.Close, 0, false) {} + public TRIX_Series(TBars source, int period) : this(source.Close, period, false) {} + public TRIX_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {} + public TRIX_Series(TSeries source, int period) : this(source, period, false, true) {} + public TRIX_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {} + + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN), update); + } + if (this.Count == 0) { _lastema1 = _lastema2 = _lastema3 = TValue.v; } + if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; } + else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; } + + double _ema1, _ema2, _ema3; + if ((this.Count < _period) && _useSMA) { + BufferTrim(_buffer1, TValue.v, _period, update); + _ema1 = 0; + for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; } + _ema1 /= _buffer1.Count; + + BufferTrim(_buffer2, _ema1, _period, update); + _ema2 = 0; + for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; } + _ema2 /= _buffer2.Count; + + BufferTrim(_buffer3, _ema2, _period, update); + _ema3 = 0; + for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; } + _ema3 /= _buffer3.Count; + } + else { + _ema1 = (TValue.v - _lastema1) * _k + _lastema1; + _ema2 = (_ema1 - _lastema2) * _k + _lastema2; + _ema3 = (_ema2 - _lastema3) * _k + _lastema3; + } + double _trix = 100 * (_ema3 - _lastema3) / _lastema3; + _lastema1 = _ema1; + _lastema2 = _ema2; + _lastema3 = _ema3; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _trix); + return base.Add(res, update); + } + +//variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + + } +} \ No newline at end of file diff --git a/Calculations/_Updated/TSeries.cs b/Calculations/_Updated/TSeries.cs new file mode 100644 index 00000000..65c09886 --- /dev/null +++ b/Calculations/_Updated/TSeries.cs @@ -0,0 +1,85 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Data; +using System.Linq; + +/* +TSeries is the cornerstone of all QuanTAlib classes. + TSeries is a single List of tuples (time, value) and contains several operators, casts, overloads + and other helpers that simplify usage of library. + Think of TSeries as an equivalent of Numpy array. + + - includes Length property (to mimic array's method) + - includes publishing and subscribing methods that attach to events + + */ +public class TSeriesEventArgs : EventArgs { + public bool update { get; set; } +} + +public class TSeries : List<(DateTime t, double v)> { + public List t => this.Select(item => item.t).ToList(); + public List v => this.Select(item => item.v).ToList(); + public (DateTime t, double v) Last => this[^1]; + public int Length => Count; + public string Name { get; set; } + + public TSeries() { + this.Name = "data"; + } + + public TSeries(string Name) { + this.Name = Name; + } + + public virtual (DateTime t, double v) Add(double v, bool update = false) { + var Value = (t: Count == 0 ? DateTime.Today : this[^1].t.AddDays(1), v); + return Add(Value, update); + } + + public virtual (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (update) { + this[^1] = TValue; + } + else { + base.Add(TValue); + } + + OnEvent(update); + return TValue; + } + + public virtual (DateTime t, double v) Add(TSeries data) { + foreach (var item in data) { Add(item, false); } + return data.Last; + } + + public void Sub(object source, TSeriesEventArgs e) { + var data = (TSeries) source; + if (data == null) { return; } + foreach (var item in data) { Add(item, update: false); } + } + + public delegate void NewEventHandler(object source, TSeriesEventArgs args); + + public event NewEventHandler Pub; + + protected virtual void OnEvent(bool update = false) + { + Pub?.Invoke(this, new TSeriesEventArgs {update = update}); + } + + /// common helpers + public static void BufferTrim(List buffer, double value, int period, bool update) { + if (!update) { + buffer.Add(value); + if (buffer.Count > period && period > 0) { buffer.RemoveAt(0); } + return; + } + buffer[^1] = value; + } + public virtual void Reset() { + } +} diff --git a/Calculations/_Updated/VAR_Series.cs b/Calculations/_Updated/VAR_Series.cs new file mode 100644 index 00000000..97ad50c3 --- /dev/null +++ b/Calculations/_Updated/VAR_Series.cs @@ -0,0 +1,84 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +VAR: Population Variance + Population variance without Bessel's correction + +Sources: + https://en.wikipedia.org/wiki/Variance + Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction + +Remark: + VAR (Population Variance) is also known as a biased Sample Variance. For unbiased + sample variance use SVAR instead. + + */ + +public class VAR_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public VAR_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"VAR({period})"; + } + public VAR_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public VAR_Series() : this(period: 0, useNaN: false) { } + public VAR_Series(int period) : this(period: period, useNaN: false) { } + public VAR_Series(TBars source) : this(source.Close, 0, false) { } + public VAR_Series(TBars source, int period) : this(source.Close, period, false) { } + public VAR_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public VAR_Series(TSeries source) : this(source, 0, false) { } + public VAR_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + double _pvar = 0; + for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } + _pvar /= this._buffer.Count; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _pvar); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/WMAPE_Series.cs b/Calculations/_Updated/WMAPE_Series.cs new file mode 100644 index 00000000..b7254958 --- /dev/null +++ b/Calculations/_Updated/WMAPE_Series.cs @@ -0,0 +1,85 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +WMAPE: Weighted Mean Absolute Percentage Error + Measures the size of the error in percentage terms. Improves problems with MAPE + when there are zero or close-to-zero values because there would be a division by zero + or values of MAPE tending to infinity. + +Sources: + https://en.wikipedia.org/wiki/WMAPE + + */ + +public class WMAPE_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public WMAPE_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"WMAPE({period})"; + } + public WMAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public WMAPE_Series() : this(period: 0, useNaN: false) { } + public WMAPE_Series(int period) : this(period: period, useNaN: false) { } + public WMAPE_Series(TBars source) : this(source.Close, 0, false) { } + public WMAPE_Series(TBars source, int period) : this(source.Close, period, false) { } + public WMAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public WMAPE_Series(TSeries source) : this(source, 0, false) { } + public WMAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + double _div = 0; + double _wmape = 0; + for (int i = 0; i < _buffer.Count; i++) { + _wmape += Math.Abs(_buffer[i] - _sma); + _div += Math.Abs(_buffer[i]); + } + _wmape = (_div != 0) ? _wmape / _div : double.PositiveInfinity; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _wmape); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/WMA_Series.cs b/Calculations/_Updated/WMA_Series.cs new file mode 100644 index 00000000..f8d8bb39 --- /dev/null +++ b/Calculations/_Updated/WMA_Series.cs @@ -0,0 +1,107 @@ +namespace QuanTAlib; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +/* +WMA: (linearly) Weighted Moving Average + 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 : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + private System.Collections.Generic.List _weights = new(); + protected int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + protected int _len; + public int Len { + get { return _len; } + set { _len = value; } + } + + //core constructors + public WMA_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"WMA({period})"; + _len = 1; + _weights = CalculateWeights(_period); + } + public WMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public WMA_Series() : this(period: 0, useNaN: false) { } + public WMA_Series(int period) : this(period: period, useNaN: false) { } + public WMA_Series(TBars source) : this(source.Close, 0, false) { } + public WMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public WMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public WMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update=false) { + BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update); + if (_period == 0) { + _weights = CalculateWeights(_len); + _len++; + } + double _wma = 0; + double totalWeights = (_buffer.Count * (_buffer.Count + 1)) * 0.5; + object lockObj = new object(); + Parallel.For(0, _buffer.Count, i => + { + double temp = _buffer[i] * this._weights[i]; + lock (lockObj) { _wma += temp; } + }); + _wma /= totalWeights; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _wma); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //calculating weights + private static List CalculateWeights(int period) { + List weights = new List(period); + for (int i = 0; i < period; i++) { + weights.Add(i + 1); + } + return weights; + } + + //reset calculation + public override void Reset() { + _len = 0; + _weights = CalculateWeights(_period); + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/ZLEMA_Series.cs b/Calculations/_Updated/ZLEMA_Series.cs new file mode 100644 index 00000000..81ad2d67 --- /dev/null +++ b/Calculations/_Updated/ZLEMA_Series.cs @@ -0,0 +1,97 @@ +namespace QuanTAlib; + +using System; +using System.Linq; + +/* +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 : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + private int _len; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private readonly EMA_Series _ema; + + //core constructor + public ZLEMA_Series(int period, bool useNaN, bool useSMA) : base() { + _period = period; + _NaN = useNaN; + Name = $"ZLEMA({period})"; + _len = 1; + _ema = new(period); + } + //generic constructors (source) + + public ZLEMA_Series() : this(0, false, true) { } + public ZLEMA_Series(int period) : this(period, false, true) { } + public ZLEMA_Series(TBars source) : this(source.Close, 0, false) { } + public ZLEMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public ZLEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public ZLEMA_Series(TSeries source, int period) : this(source, period, false, true) { } + public ZLEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { } + public ZLEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) { + BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update); + int _lag; + if (_period == 0) { + _lag = (int)((_len - 1) * 0.5); + _len++; + } + else { _lag = (int)((_period - 1) * 0.5); } + _lag = Math.Min(_lag, _buffer.Count - 1); + _lag = Math.Max(_lag, 0) + 1; + double _zlValue = 2 * TValue.v - _buffer[^_lag]; + double _zlema = _ema.Add((TValue.t, _zlValue), update).v; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zlema); + return base.Add(res, update); + } + + //variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + _ema.Reset(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/ZL_Series.cs b/Calculations/_Updated/ZL_Series.cs new file mode 100644 index 00000000..cfb71d20 --- /dev/null +++ b/Calculations/_Updated/ZL_Series.cs @@ -0,0 +1,93 @@ +namespace QuanTAlib; + +using System; +using System.Linq; + +/* +ZL: Zero Lag + Data is de-lagged by removing the data from “lag” days ago, thus removing + (or attempting to) the cumulative effect of the moving average. + +Calculation: + Lag = (Period-1)/2 + ZL = Data + (Data - Data(Lag days ago) ) + +Sources: + https://mudrex.com/blog/zero-lag-ema-trading-strategy/ + + */ + +public class ZL_Series: TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + private int _len; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private readonly EMA_Series _ema; + + //core constructor + public ZL_Series(int period, bool useNaN, bool useSMA) : base() { + _period = period; + _NaN = useNaN; + Name = $"ZL({period})"; + _len = 1; + _ema = new(period); + } + //generic constructors (source) + + public ZL_Series() : this(0, false, true) { } + public ZL_Series(int period) : this(period, false, true) { } + public ZL_Series(TBars source) : this(source.Close, 0, false) { } + public ZL_Series(TBars source, int period) : this(source.Close, period, false) { } + public ZL_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public ZL_Series(TSeries source, int period) : this(source, period, false, true) { } + public ZL_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { } + public ZL_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) { + BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update); + int _lag; + if (_period == 0) { + _lag = (int)((_len - 1) * 0.5); + _len++; + } + else { _lag = (int)((_period - 1) * 0.5); } + _lag = Math.Min(_lag, _buffer.Count - 1); + _lag = Math.Max(_lag, 0) + 1; + double _zlValue = 2 * TValue.v - _buffer[^_lag]; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zlValue); + return base.Add(res, update); + } + + //variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + _ema.Reset(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/ZSCORE_Series.cs b/Calculations/_Updated/ZSCORE_Series.cs new file mode 100644 index 00000000..8b213c04 --- /dev/null +++ b/Calculations/_Updated/ZSCORE_Series.cs @@ -0,0 +1,91 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +ZSCORE: number of standard deviations from SMA + Z-score describes a value's relationship to the mean of a series, as measured in + terms of standard deviations from the mean. If a Z-score is 0, it indicates that + the data point's score is identical to the mean score. A Z-score of 1.0 would + indicate a value that is one standard deviation from the mean. Z-scores may be + positive or negative, with a positive value indicating the score is above the + mean and a negative score indicating it is below the mean. + +Sources: + https://en.wikipedia.org/wiki/Z-score + https://www.investopedia.com/terms/z/zscore.asp + +Calculation: + std = std * STDEV(close, length) + mean = SMA(close, length) + ZSCORE = (close - mean) / std + + */ + +public class ZSCORE_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public ZSCORE_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"ZSCORE({period})"; + } + public ZSCORE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public ZSCORE_Series() : this(period: 0, useNaN: false) { } + public ZSCORE_Series(int period) : this(period: period, useNaN: false) { } + public ZSCORE_Series(TBars source) : this(source.Close, 0, false) { } + public ZSCORE_Series(TBars source, int period) : this(source.Close, period, false) { } + public ZSCORE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public ZSCORE_Series(TSeries source) : this(source, 0, false) { } + public ZSCORE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + double _sma = _buffer.Average(); + + double _pvar = 0; + for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } + _pvar /= this._buffer.Count; + double _psdev = Math.Sqrt(_pvar); + double _zscore = (_psdev == 0) ? 1 : (TValue.v - _sma) / _psdev; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zscore); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/zMA_Series.cs b/Calculations/_Updated/zMA_Series.cs new file mode 100644 index 00000000..c37a41e5 --- /dev/null +++ b/Calculations/_Updated/zMA_Series.cs @@ -0,0 +1,72 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* + + */ + +public class xMA_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public xMA_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"xMA({period})"; + } + public xMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public xMA_Series() : this(period: 0, useNaN: false) { } + public xMA_Series(int period) : this(period: period, useNaN: false) { } + public xMA_Series(TBars source) : this(source.Close, 0, false) { } + public xMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public xMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public xMA_Series(TSeries source) : this(source, 0, false) { } + public xMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN), update); + } + + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _xma = 0; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _xma); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Indicators/Charts/2MACross_chart.cs b/Indicators/Charts/2MACross_chart.cs index 279dab74..2bc81b8e 100644 --- a/Indicators/Charts/2MACross_chart.cs +++ b/Indicators/Charts/2MACross_chart.cs @@ -7,7 +7,7 @@ namespace QuanTAlib; public class MovingAverage_chart : Indicator { #region Parameters [InputParameter("MA1: Type:", 0, variants: new object[] - { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FMA", 7, "DEMA", 8, "TEMA", 9, + { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9, "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})] private int MA1type = 15; @@ -20,7 +20,7 @@ public class MovingAverage_chart : Indicator { private int MA1DataSource = 3; [InputParameter("MA2: Type:", 3, variants: new object[] - { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FMA", 7, "DEMA", 8, "TEMA", 9, + { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9, "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})] private int MA2type = 16; @@ -97,8 +97,8 @@ public class MovingAverage_chart : Indicator { this.Name += $"DWMA"; break; case 7: - MA1 = new FMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period); - this.Name += $"FMA"; + MA1 = new FWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period); + this.Name += $"FWMA"; break; case 8: MA1 = new DEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false); @@ -171,8 +171,8 @@ public class MovingAverage_chart : Indicator { this.Name += $"DWMA"; break; case 7: - MA2 = new FMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period); - this.Name += $"FMA"; + MA2 = new FWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period); + this.Name += $"FWMA"; break; case 8: MA2 = new DEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false); diff --git a/Indicators/Charts/2MASlope_chart.cs b/Indicators/Charts/2MASlope_chart.cs index 4f65c53e..360af677 100644 --- a/Indicators/Charts/2MASlope_chart.cs +++ b/Indicators/Charts/2MASlope_chart.cs @@ -7,7 +7,7 @@ namespace QuanTAlib; public class MovingAverageSlope_chart : Indicator { #region Parameters [InputParameter("MA1: Type:", 0, variants: new object[] - { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FMA", 7, "DEMA", 8, "TEMA", 9, + { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9, "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})] private int MA1type = 16; @@ -20,7 +20,7 @@ public class MovingAverageSlope_chart : Indicator { private int MA1DataSource = 3; [InputParameter("MA2: Type:", 3, variants: new object[] - { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FMA", 7, "DEMA", 8, "TEMA", 9, + { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9, "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})] private int MA2type = 6; @@ -101,8 +101,8 @@ public class MovingAverageSlope_chart : Indicator { this.Name += $"DWMA"; break; case 7: - MA1 = new FMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period); - this.Name += $"FMA"; + MA1 = new FWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period); + this.Name += $"FWMA"; break; case 8: MA1 = new DEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false); @@ -175,8 +175,8 @@ public class MovingAverageSlope_chart : Indicator { this.Name += $"DWMA"; break; case 7: - MA2 = new FMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period); - this.Name += $"FMA"; + MA2 = new FWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period); + this.Name += $"FWMA"; break; case 8: MA2 = new DEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false); @@ -227,11 +227,7 @@ public class MovingAverageSlope_chart : Indicator { 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); + this.bars.Add(this.Time(),this.Open(), this.High(), this.Low(), this.Close(), this.Volume(), update); this.SetValue(this.MA1[^1].v, lineIndex: 0); this.SetValue(this.MA2[^1].v, lineIndex: 1); diff --git a/Indicators/Charts/JMA_chart.cs b/Indicators/Charts/JMA_chart.cs index 366d759b..9390ea59 100644 --- a/Indicators/Charts/JMA_chart.cs +++ b/Indicators/Charts/JMA_chart.cs @@ -64,9 +64,7 @@ public class JMA_chart : Indicator { rec[PriceType.Close], rec[PriceType.Volume]); } - indicator = new(source: bars.Select(DataSource), period: Period, - phase: Jphase, vshort: Vshort, vlong: Vlong, - useNaN: true); + indicator = new(source: bars.Select(DataSource), period: Period, phase: Jphase, vshort: Vshort, vlong: Vlong, useNaN: true); } protected override void OnUpdate(UpdateArgs args) { diff --git a/Indicators/Indicators.csproj b/Indicators/Indicators.csproj index 8c28acf6..0446cc33 100644 --- a/Indicators/Indicators.csproj +++ b/Indicators/Indicators.csproj @@ -17,6 +17,8 @@ 0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d 0.2.1-dev.2 NETSDK1057 + true + NETSDK1057 True diff --git a/Strategies/SimpleMACross1.cs b/Strategies/SimpleMACross1.cs index 117af5ca..f6ffaeb6 100644 --- a/Strategies/SimpleMACross1.cs +++ b/Strategies/SimpleMACross1.cs @@ -64,7 +64,7 @@ namespace SimpleMACross { bars.Add(hdm.Last().TimeLeft, hdm.Last()[PriceType.Open], hdm.Last()[PriceType.High], hdm.Last()[PriceType.Low], hdm.Last()[PriceType.Close], hdm.Last()[PriceType.Volume], update); - if (!update) {this.LogInfo($"{bars.Close.Last().t} OHLC4:{(double)bars.OHLC4}");} + if (!update) {this.LogInfo($"{bars.Close.Last().t} OHLC4:{(double)bars.OHLC4.Last.v}");} } diff --git a/Strategies/Strategies.csproj b/Strategies/Strategies.csproj index aa04c0c4..08f3bcdf 100644 --- a/Strategies/Strategies.csproj +++ b/Strategies/Strategies.csproj @@ -17,6 +17,8 @@ 0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d 0.2.1-dev.2 NETSDK1057 + true + NETSDK1057 True diff --git a/Tests/Basic tests/Indicators.cs b/Tests/Basic tests/Indicators.cs new file mode 100644 index 00000000..29476d01 --- /dev/null +++ b/Tests/Basic tests/Indicators.cs @@ -0,0 +1,153 @@ +using Xunit; +using System; +using QuanTAlib; + +namespace Basics; +#nullable disable +public class Indicators +{ + private static Type[] maSeriesTypes = new Type[] + { + typeof(SMA_Series), + typeof(EMA_Series), + typeof(DEMA_Series), + typeof(TEMA_Series), + typeof(WMA_Series), + typeof(ALMA_Series), + typeof(DWMA_Series), + typeof(FWMA_Series), + typeof(HMA_Series), + typeof(ZLEMA_Series), + typeof(RMA_Series), + typeof(HEMA_Series), + typeof(JMA_Series), + typeof(CUSUM_Series), + typeof(SMMA_Series), + typeof(T3_Series), + typeof(KAMA_Series), + typeof(TRIMA_Series), +}; + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Name_exists(Type classType) + { + TSeries data = new("Data") {1,2,3}; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + Assert.NotEmpty(MA_Series.Name); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Series_Length(Type classType) + { + GBM_Feed feed = new(1000); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + Assert.Equal(1000, MA_Series.Count); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Return_data(Type classType) + { + TSeries data = new() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + var result = MA_Series.Add(20); + Assert.Equal(result.v, MA_Series.Last.v); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Update(Type classType) + { + TSeries data = new() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + var pre_update = MA_Series.Last.v; + + double pre_data = data.Last.v; + data.Add(20, true); + data.Add(pre_data, true); + + Assert.Equal(pre_update, MA_Series.Last.v); + Assert.Equal(data.Count, MA_Series.Count); +} + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Period_zero(Type classType) + { + GBM_Feed feed = new(100); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 0, false) as TSeries; + Assert.Equal(data.Count, MA_Series.Count); + Assert.False(double.IsNaN(MA_Series.Last.v)); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Reset(Type classType) + { + GBM_Feed feed = new(10); + TSeries data = feed.OHLC4; + var MA_Series = Activator.CreateInstance(classType, data, 10, false) as TSeries; + MA_Series.Reset(); + data.Add(0); + Assert.Equal(data.Last.v, MA_Series.Last.v); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Period_one(Type classType) + { + GBM_Feed feed = new(100); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 1, false) as TSeries; + Assert.InRange(MA_Series.Last.v - data.Last.v, -10e-6, 10e-6); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void NaN_test(Type classType) + { + GBM_Feed feed = new(100); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries; + Assert.True(double.IsNaN(MA_Series[0].v)); + Assert.True(double.IsNaN(MA_Series[8].v)); + Assert.False(double.IsNaN(MA_Series[9].v)); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Edge_numbers(Type classType) + { + TSeries data = new() { double.Epsilon, double.PositiveInfinity, double.MaxValue, double.NegativeInfinity }; + var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries; + Assert.Equal(4, MA_Series.Count); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void handling_NaN(Type classType) { + TSeries data = new("Name") { 1, 2, 3, 4, 5, 6, double.NaN, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; +var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries; + Assert.False(double.IsNaN(MA_Series.Last.v)); + } + +public static IEnumerable MASeriesData() + { + foreach (var type in maSeriesTypes) + { + yield return new object[] { type }; + } + } +} +#nullable restore \ No newline at end of file diff --git a/Tests/Basic tests/Oscillators.cs b/Tests/Basic tests/Oscillators.cs new file mode 100644 index 00000000..458386fb --- /dev/null +++ b/Tests/Basic tests/Oscillators.cs @@ -0,0 +1,158 @@ +using Xunit; +using System; +using System.Runtime.InteropServices; +using QuanTAlib; + +namespace Basics; +#nullable disable +public class Oscillators +{ + private static Type[] maSeriesTypes = new Type[] + { + typeof(BIAS_Series), + typeof(MAX_Series), + typeof(MIN_Series), + typeof(MIDPOINT_Series), + typeof(ZL_Series), + typeof(DECAY_Series), + typeof(ENTROPY_Series), + typeof(KURTOSIS_Series), + typeof(MAD_Series), + typeof(MAPE_Series), + typeof(MSE_Series), + typeof(SDEV_Series), + typeof(SMAPE_Series), + typeof(WMAPE_Series), + typeof(SSDEV_Series), + typeof(VAR_Series), + typeof(SVAR_Series), + typeof(MEDIAN_Series), + typeof(ZSCORE_Series), + typeof(CMO_Series), + typeof(RSI_Series), + typeof(TRIX_Series), +}; + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Name_exists(Type classType) + { + TSeries data = new("Data") {1,2,3}; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + Assert.NotEmpty(MA_Series.Name); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Series_Length(Type classType) + { + GBM_Feed feed = new(1000); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + Assert.Equal(1000, MA_Series.Count); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Return_data(Type classType) + { + TSeries data = new() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + var result = MA_Series.Add(20); + Assert.Equal(result.v, MA_Series.Last.v); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Update(Type classType) + { + TSeries data = new() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + var pre_update = MA_Series.Last.v; + + double pre_data = data.Last.v; + data.Add(20, true); + data.Add(pre_data, true); + + Assert.Equal(pre_update, MA_Series.Last.v); + Assert.Equal(data.Count, MA_Series.Count); +} + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Period_zero(Type classType) + { + GBM_Feed feed = new(100); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 0, false) as TSeries; + Assert.Equal(data.Count, MA_Series.Count); + Assert.False(double.IsNaN(MA_Series.Last.v)); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Reset(Type classType) + { + GBM_Feed feed = new(10); + TSeries data = feed.OHLC4; + var MA_Series = Activator.CreateInstance(classType, data, 10, false) as TSeries; + MA_Series.Reset(); + data.Add(1); + Assert.False(double.IsNaN(MA_Series.Last.v)); +} + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Period_one(Type classType) + { + GBM_Feed feed = new(100); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 1, false) as TSeries; + Assert.False(double.IsNaN(MA_Series[^1].v)); +} + + [Theory] + [MemberData(nameof(MASeriesData))] + public void NaN_test(Type classType) + { + GBM_Feed feed = new(100); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries; + Assert.True(double.IsNaN(MA_Series[0].v)); + Assert.True(double.IsNaN(MA_Series[8].v)); + Assert.False(double.IsNaN(MA_Series[9].v)); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Edge_numbers(Type classType) + { + TSeries data = new() { double.Epsilon, double.PositiveInfinity, double.MaxValue, double.NegativeInfinity }; + var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries; + Assert.Equal(4, MA_Series.Count); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void handling_NaN(Type classType) { + TSeries data = new("Name") { 1, 2, 3, 4, 5, 6, double.NaN, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; +var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries; + Assert.False(double.IsNaN(MA_Series.Last.v)); + } + +public static IEnumerable MASeriesData() + { + foreach (var type in maSeriesTypes) + { + yield return new object[] { type }; + } + } +} +#nullable restore \ No newline at end of file diff --git a/Tests/Basics/Abstract_Test.cs b/Tests/Basics/Abstract_Test.cs deleted file mode 100644 index b2ffb9a3..00000000 --- a/Tests/Basics/Abstract_Test.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Basics; -public class Abstract_Test -{ - [Fact] - public void Single_Add_variations() - { - TSeries s = new() { 1,2,3,4,5 }; - SMA_Series a = new(s, 3) - { - { (DateTime.Today, 10), true } - }; - Assert.Equal(s.Length, a.Length); - a.Add(true); - Assert.Equal(s.Length, a.Length); - a.Add(); - Assert.Equal(s.Length+1, a.Length); - } - -} diff --git a/Tests/Basics/TSeries_Test.cs b/Tests/Basics/TSeries_Test.cs deleted file mode 100644 index 2344e85c..00000000 --- a/Tests/Basics/TSeries_Test.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Basics; -public class TSeries_Test -{ - [Fact] - public void InsertingTuple() - { - TSeries s = new() { (t: DateTime.Today, v: double.Epsilon) }; - Assert.Equal((DateTime.Today, double.Epsilon), s[^1]); - } - - [Fact] - public void CastingTwoParameters() - { - TSeries s = new() - { - { DateTime.Today, 0.0 } - }; - Assert.Equal(0.0, s[s.Count - 1].v); - Assert.Equal(DateTime.Today, s[s.Count - 1].t); - } - - [Fact] - public void CastingOneParameter() - { - TSeries s = new() - { - double.PositiveInfinity - }; - Assert.Equal(double.PositiveInfinity, (double)s); - } - - [Fact] - public void UpdatingValue() - { - TSeries s = new() { 1, 2, 3, 4, 5 }; - s.Add(0.0, update: true); - Assert.Equal(0.0, (double)s); - Assert.Equal(5, s.Count); - } - [Fact] - public void ReflectingSeries() - { - TSeries s = new() { 1, 2, 3, 4, 5 }; - TSeries t = s; - Assert.Equal(5, (double)t); - Assert.Equal(5, t.Count); - } - [Fact] - public void BroadcastingEvents() - { - TSeries s = new() { 1, 2, 3, 4, 5 }; - TSeries t = new(); - 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 deleted file mode 100644 index b35e0d4b..00000000 --- a/Tests/MovingAvg/ALMA_Test.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class Update -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { Double.NaN, 0, 1, 2, 3, 4 }; - ALMA_Series c = new(a, 4); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(10, update: true); - Assert.Equal(a.Count, c.Count); - Assert.Equal(0, a[1].v); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - ALMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 842caacf..00000000 --- a/Tests/MovingAvg/BBANDS_Test.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class BBANDS_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - BBANDS_Series c = new(a, 4,2.5); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - Assert.Equal(a.Count, c.Mid.Count); - Assert.Equal(a.Count, c.Upper.Count); - Assert.Equal(a.Count, c.Lower.Count); - Assert.Equal(a.Count, c.PercentB.Count); - Assert.Equal(a.Count, c.Zscore.Count); - Assert.Equal(a.Count, c.Bandwidth.Count); - - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - Assert.Equal(a.Count, c.Mid.Count); - Assert.Equal(a.Count, c.Upper.Count); - Assert.Equal(a.Count, c.Lower.Count); - Assert.Equal(a.Count, c.PercentB.Count); - Assert.Equal(a.Count, c.Zscore.Count); - Assert.Equal(a.Count, c.Bandwidth.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - BBANDS_Series c = new(a, 4, 2.5); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - Assert.Equal(a.Count, c.Mid.Count); - Assert.Equal(a.Count, c.Upper.Count); - Assert.Equal(a.Count, c.Lower.Count); - Assert.Equal(a.Count, c.PercentB.Count); - Assert.Equal(a.Count, c.Zscore.Count); - Assert.Equal(a.Count, c.Bandwidth.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - Assert.Equal(a.Count, c.Mid.Count); - Assert.Equal(a.Count, c.Upper.Count); - Assert.Equal(a.Count, c.Lower.Count); - 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 deleted file mode 100644 index 7ce76446..00000000 --- a/Tests/MovingAvg/DEMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class DEMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - DEMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - DEMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} diff --git a/Tests/MovingAvg/DWMA_Test.cs b/Tests/MovingAvg/DWMA_Test.cs deleted file mode 100644 index 471f1713..00000000 --- a/Tests/MovingAvg/DWMA_Test.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class DWMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { Double.NaN, 0, 1, 2, 3, 4 }; - DWMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - Assert.Equal(0, a[1].v); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - DWMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index fddc3279..00000000 --- a/Tests/MovingAvg/EMA_Test.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class EMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { Double.NaN, 0, 1, 2, 3, 4 }; - EMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - Assert.Equal(0, a[1].v); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - EMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} diff --git a/Tests/MovingAvg/FMA_Test.cs b/Tests/MovingAvg/FMA_Test.cs deleted file mode 100644 index 2369784d..00000000 --- a/Tests/MovingAvg/FMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class FMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - FMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - FMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index eaed9490..00000000 --- a/Tests/MovingAvg/HEMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class HEMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - HEMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - HEMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index e2cd00dc..00000000 --- a/Tests/MovingAvg/HMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class HMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - HMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - HMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 2623d325..00000000 --- a/Tests/MovingAvg/JMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class JMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - JMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - JMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 87714240..00000000 --- a/Tests/MovingAvg/KAMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class KAMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - KAMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - KAMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index dd0ee4ad..00000000 --- a/Tests/MovingAvg/MACD_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class MACD_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MACD_Series c = new(a, 26,12,9); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MACD_Series c = new(a, 26,12,9); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 6bdea4ff..00000000 --- a/Tests/MovingAvg/RMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class RMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - RMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - RMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 016c0391..00000000 --- a/Tests/MovingAvg/RSI_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class RSI_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - RSI_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - RSI_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index b08b268f..00000000 --- a/Tests/MovingAvg/SMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class SMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 418fe695..00000000 --- a/Tests/MovingAvg/SMMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class SMMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SMMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SMMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index af7b0df9..00000000 --- a/Tests/MovingAvg/TEMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class TEMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - TEMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - TEMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 52e12045..00000000 --- a/Tests/MovingAvg/WMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class WMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - WMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - WMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index dad74ec0..00000000 --- a/Tests/MovingAvg/ZLEMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class ZLEMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - ZLEMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - ZLEMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} diff --git a/Tests/Basics/ADD_Test.cs b/Tests/Pairs/ADD_Test.cs similarity index 98% rename from Tests/Basics/ADD_Test.cs rename to Tests/Pairs/ADD_Test.cs index 66e2f122..2c86e5a8 100644 --- a/Tests/Basics/ADD_Test.cs +++ b/Tests/Pairs/ADD_Test.cs @@ -2,7 +2,7 @@ using Xunit; using System; using QuanTAlib; -namespace Basics; +namespace Pairs; public class ADD_Test { [Fact] diff --git a/Tests/Basics/DIV_Test.cs b/Tests/Pairs/DIV_Test.cs similarity index 98% rename from Tests/Basics/DIV_Test.cs rename to Tests/Pairs/DIV_Test.cs index 0421bff8..a8286017 100644 --- a/Tests/Basics/DIV_Test.cs +++ b/Tests/Pairs/DIV_Test.cs @@ -2,7 +2,7 @@ using Xunit; using System; using QuanTAlib; -namespace Basics; +namespace Pairs; public class DIV_Test { [Fact] diff --git a/Tests/Basics/MUL_Test.cs b/Tests/Pairs/MUL_Test.cs similarity index 98% rename from Tests/Basics/MUL_Test.cs rename to Tests/Pairs/MUL_Test.cs index 30d1d536..90ad3888 100644 --- a/Tests/Basics/MUL_Test.cs +++ b/Tests/Pairs/MUL_Test.cs @@ -2,7 +2,7 @@ using Xunit; using System; using QuanTAlib; -namespace Basics; +namespace Pairs; public class MUL_Test { [Fact] diff --git a/Tests/Basics/SUB_Test.cs b/Tests/Pairs/SUB_Test.cs similarity index 98% rename from Tests/Basics/SUB_Test.cs rename to Tests/Pairs/SUB_Test.cs index b9f18584..04775464 100644 --- a/Tests/Basics/SUB_Test.cs +++ b/Tests/Pairs/SUB_Test.cs @@ -2,7 +2,7 @@ using Xunit; using System; using QuanTAlib; -namespace Basics; +namespace Pairs; public class SUB_Test { [Fact] diff --git a/Tests/Basics/TBars_Test.cs b/Tests/Pairs/TBars_Test.cs similarity index 95% rename from Tests/Basics/TBars_Test.cs rename to Tests/Pairs/TBars_Test.cs index bc49e764..531703bc 100644 --- a/Tests/Basics/TBars_Test.cs +++ b/Tests/Pairs/TBars_Test.cs @@ -1,112 +1,112 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Basics; -public class TBars_Test -{ - [Fact] - public void InsertingTuple() - { - TBars s = new() { (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue, c: Double.NegativeInfinity, v: Double.PositiveInfinity) }; - var tup = (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue, - c: Double.NegativeInfinity, v: Double.PositiveInfinity); - Assert.Equal(tup, s[^1]); - } - - [Fact] - public void Casting_Parameters() - { - TBars s = new() - { - { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false } - }; - Assert.Equal(0.1, s[^1].o); - Assert.Equal(1.1, s[^1].h); - Assert.Equal(2.1, s[^1].l); - Assert.Equal(3.1, s[^1].c); - Assert.Equal(4.1, s[^1].v); - Assert.Equal(DateTime.Today, s[^1].t); - Assert.Single(s); - } - - [Fact] - public void Updating_Value() - { - TBars s = new() - { - { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 } - }; - s.Add(DateTime.Today, 1.0, 1.0, 1.0, 1.0, 1.0, update: false); - s.Add(DateTime.Today, 0.0, 0.0, 0.0, 0.0, 0.0, update: true); - Assert.Equal(0.0, s[^1].o); - Assert.Equal(0.0, s[^1].h); - Assert.Equal(0.0, s[^1].l); - Assert.Equal(0.0, s[^1].c); - Assert.Equal(0.0, s[^1].v); - Assert.Equal(2, s.Count); - } - [Fact] - public void Extracting_TSeries() - { - TBars s = new() - { - { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 }, - { DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1 } - }; - - TSeries t = s.Open; - Assert.Equal(t.t, s.Open.t); - Assert.Equal(t.v, s.Open.v); - - t = s.High; - Assert.Equal(t.t, s.High.t); - Assert.Equal(t.v, s.High.v); - - t = s.Low; - Assert.Equal(t.t, s.Low.t); - Assert.Equal(t.v, s.Low.v); - - t = s.Close; - Assert.Equal(t.t, s.Close.t); - Assert.Equal(t.v, s.Close.v); - - t = s.Volume; - Assert.Equal(t.t, s.Volume.t); - Assert.Equal(t.v, s.Volume.v); - - t = s.HL2; - Assert.Equal(t.t, s.HL2.t); - Assert.Equal(t.v, s.HL2.v); - - t = s.OC2; - Assert.Equal(t.t, s.OC2.t); - Assert.Equal(t.v, s.OC2.v); - - t = s.OHL3; - Assert.Equal(t.t, s.OHL3.t); - Assert.Equal(t.v, s.OHL3.v); - - t = s.HLC3; - Assert.Equal(t.t, s.HLC3.t); - Assert.Equal(t.v, s.HLC3.v); - - t = s.OHLC4; - Assert.Equal(t.t, s.OHLC4.t); - Assert.Equal(t.v, s.OHLC4.v); - - t = s.HLCC4; - Assert.Equal(t.t, s.HLCC4.t); - Assert.Equal(t.v, s.HLCC4.v); - } - [Fact] - public void Broadcasting_Events() - { - TBars s = new() { (DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1) }; - TSeries t = new(); - s.Close.Pub += t.Sub; - 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); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Bars; +public class TBars_Test +{ + [Fact] + public void InsertingTuple() + { + TBars s = new() { (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue, c: Double.NegativeInfinity, v: Double.PositiveInfinity) }; + var tup = (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue, + c: Double.NegativeInfinity, v: Double.PositiveInfinity); + Assert.Equal(tup, s[^1]); + } + + [Fact] + public void Casting_Parameters() + { + TBars s = new() + { + { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false } + }; + Assert.Equal(0.1, s[^1].o); + Assert.Equal(1.1, s[^1].h); + Assert.Equal(2.1, s[^1].l); + Assert.Equal(3.1, s[^1].c); + Assert.Equal(4.1, s[^1].v); + Assert.Equal(DateTime.Today, s[^1].t); + Assert.Single(s); + } + + [Fact] + public void Updating_Value() + { + TBars s = new() + { + { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 } + }; + s.Add(DateTime.Today, 1.0, 1.0, 1.0, 1.0, 1.0, update: false); + s.Add(DateTime.Today, 0.0, 0.0, 0.0, 0.0, 0.0, update: true); + Assert.Equal(0.0, s[^1].o); + Assert.Equal(0.0, s[^1].h); + Assert.Equal(0.0, s[^1].l); + Assert.Equal(0.0, s[^1].c); + Assert.Equal(0.0, s[^1].v); + Assert.Equal(2, s.Count); + } + [Fact] + public void Extracting_TSeries() + { + TBars s = new() + { + { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 }, + { DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1 } + }; + + TSeries t = s.Open; + Assert.Equal(t.t, s.Open.t); + Assert.Equal(t.v, s.Open.v); + + t = s.High; + Assert.Equal(t.t, s.High.t); + Assert.Equal(t.v, s.High.v); + + t = s.Low; + Assert.Equal(t.t, s.Low.t); + Assert.Equal(t.v, s.Low.v); + + t = s.Close; + Assert.Equal(t.t, s.Close.t); + Assert.Equal(t.v, s.Close.v); + + t = s.Volume; + Assert.Equal(t.t, s.Volume.t); + Assert.Equal(t.v, s.Volume.v); + + t = s.HL2; + Assert.Equal(t.t, s.HL2.t); + Assert.Equal(t.v, s.HL2.v); + + t = s.OC2; + Assert.Equal(t.t, s.OC2.t); + Assert.Equal(t.v, s.OC2.v); + + t = s.OHL3; + Assert.Equal(t.t, s.OHL3.t); + Assert.Equal(t.v, s.OHL3.v); + + t = s.HLC3; + Assert.Equal(t.t, s.HLC3.t); + Assert.Equal(t.v, s.HLC3.v); + + t = s.OHLC4; + Assert.Equal(t.t, s.OHLC4.t); + Assert.Equal(t.v, s.OHLC4.v); + + t = s.HLCC4; + Assert.Equal(t.t, s.HLCC4.t); + Assert.Equal(t.v, s.HLCC4.v); + } + [Fact] + public void Broadcasting_Events() + { + TBars s = new() { (DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1) }; + TSeries t = new(); + s.Close.Pub += t.Sub; + 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/Series/Update.cs b/Tests/Series/Update.cs deleted file mode 100644 index 91fa9439..00000000 --- a/Tests/Series/Update.cs +++ /dev/null @@ -1,545 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; -using Skender.Stock.Indicators; - -namespace Series; -public class Update { - private readonly GBM_Feed bars; - private readonly Random rnd = new(); - private readonly int period; - - public Update() { - bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0); - period = rnd.Next(28) + 3; - } - - [Fact] public void ADL() { - ADL_Series QL = new(bars); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void ADOSC() { - ADOSC_Series QL = new(bars); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void ALMA() { - ALMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void ATR() { - ATR_Series QL = new(bars, period: period); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void ATRP() { - ATRP_Series QL = new(bars, period: period); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void BBANDS() { - BBANDS_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void BIAS() { - BIAS_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void CCI() { - CCI_Series QL = new(bars, period: period); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void CORR() { - CORR_Series QL = new(d1: bars.High, d2: bars.Low, period: period); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), (DateTime.Today, 0), update: true); - QL.Add((lastData.t, lastData.h), (lastData.t, lastData.l), update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void COVAR() { - COVAR_Series QL = new(d1: bars.High, d2: bars.Low, period); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), (DateTime.Today, 0), update: true); - QL.Add((lastData.t, lastData.h), (lastData.t, lastData.l), update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] - public void DECAY() { - DECAY_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void DEMA() { - DEMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] - public void DWMA() { - DWMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void ENTROPY() { - ENTROPY_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void EMA() { - EMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] - public void FMA() { - FMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void HEMA() { - HEMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void HMA() { - HMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] - public void HWMA() { - HWMA_Series QL = new(source: bars.Close); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void JMA() { - JMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void KAMA() { - KAMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void KURTOSIS() { - KURTOSIS_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void LINREG() { - LINREG_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MACD() { - MACD_Series QL = new(source: bars.Close); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - var lastC1 = QL.Signal.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - Assert.Equal(lastC1, QL.Signal.Last()); // same data - } - [Fact] public void MAD() { - MAD_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MAMA() { - MAMA_Series QL = new(source: bars.Close); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - var lastC1 = QL.Fama.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - Assert.Equal(lastC1, QL.Fama.Last()); // same data - } - [Fact] public void MAPE() { - MAPE_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MAX() { - MAX_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MEDIAN() { - MEDIAN_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MIDPOINT() { - MIDPOINT_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MIDPRICE() { - MIDPRICE_Series QL = new(bars, period: period); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MIN() { - MAX_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MSE() { - MSE_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void OBV() { - OBV_Series QL = new(bars, period: period); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void RSI() { - RSI_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void RMA() { - RMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void SDEV() { - SDEV_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void SMA() { - SMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void SMAPE() { - SMAPE_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void SMMA() { - SMMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void SSDEV() { - SSDEV_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void SUM() { - SUM_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void SVAR() { - SVAR_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void T3() { - SMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void TEMA() { - TEMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void TR() { - TR_Series QL = new(bars); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void TRIMA() { - TRIMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void VAR() { - VAR_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void WMA() { - WMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void WMAPE() { - WMAPE_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void ZLEMA() { - ZLEMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void ZSCORE() { - ZSCORE_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } -} diff --git a/Tests/Statistics/BIAS_Test.cs b/Tests/Statistics/BIAS_Test.cs deleted file mode 100644 index 2b46429c..00000000 --- a/Tests/Statistics/BIAS_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class BIAS_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - BIAS_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - BIAS_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index f7e8aa10..00000000 --- a/Tests/Statistics/ENTP_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class KURTOSIS_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - KURTOSIS_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - KURTOSIS_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index c594ff4b..00000000 --- a/Tests/Statistics/KURT_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class ENTP_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - ENTROPY_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - ENTROPY_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 19cbf086..00000000 --- a/Tests/Statistics/LINREG_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class LINREG_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - LINREG_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - LINREG_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index fcc11764..00000000 --- a/Tests/Statistics/MAD_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MAD_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MAD_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MAD_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 1052f136..00000000 --- a/Tests/Statistics/MAPE_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MAPE_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MAPE_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MAPE_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 785af747..00000000 --- a/Tests/Statistics/MAX_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MAX_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MAX_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MAX_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index ccfc2bcc..00000000 --- a/Tests/Statistics/MED_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MED_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MEDIAN_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MEDIAN_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 917879d8..00000000 --- a/Tests/Statistics/MIN_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MIN_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MIN_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MIN_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 4c8374b7..00000000 --- a/Tests/Statistics/MSE_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MSE_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MSE_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MSE_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index fa871ddb..00000000 --- a/Tests/Statistics/PSDEV_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class PSDEV_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SDEV_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SDEV_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index ef3880b4..00000000 --- a/Tests/Statistics/PVAR_Test .cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class PVAR_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SVAR_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SVAR_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index e8b76a5d..00000000 --- a/Tests/Statistics/SDEV_Test .cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class SDEV_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SSDEV_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SSDEV_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index fcc01a44..00000000 --- a/Tests/Statistics/SMAPE_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class SMAPE_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SMAPE_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SMAPE_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 329cd1f5..00000000 --- a/Tests/Statistics/VAR_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class VAR_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SVAR_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SVAR_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 54acfbe5..00000000 --- a/Tests/Statistics/WMAPE_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class WMAPE_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - WMAPE_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - WMAPE_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index fb878d36..07aed4a3 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -1,6 +1,6 @@  - net6.0 + net8.0 preview enable enable @@ -10,6 +10,8 @@ 0.2.1.0 0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d 0.2.1-dev.2 + $(NoWarn);NETSDK1057 + true @@ -38,4 +40,7 @@ + + + \ No newline at end of file diff --git a/Tests/Validations/Trends/TA_LIB.cs b/Tests/Validations/Trends/TA_LIB.cs index 1d211ba6..11282618 100644 --- a/Tests/Validations/Trends/TA_LIB.cs +++ b/Tests/Validations/Trends/TA_LIB.cs @@ -388,7 +388,7 @@ public class Ta_Lib [Fact] public void SUM() { - SUM_Series QL = new(bars.Close, period, false); + CUSUM_Series QL = new(bars.Close, period, false); Core.Sum(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); for (int i = QL.Length - 1; i > skip; i--) { diff --git a/Tests/Validations/Trends/Tulip.cs b/Tests/Validations/Trends/Tulip.cs index a205b635..959b16d4 100644 --- a/Tests/Validations/Trends/Tulip.cs +++ b/Tests/Validations/Trends/Tulip.cs @@ -426,7 +426,7 @@ public class Tulip_Test public void SUM() { double[][] arrin = { inclose }; double[][] arrout = { outdata }; - SUM_Series QL = new(bars.Close, period, false); + CUSUM_Series QL = new(bars.Close, period, false); Tulip.Indicators.sum.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = QL[i].v; From 3b71ac70c8a57c2550227035a8b82990d1d7ea1d Mon Sep 17 00:00:00 2001 From: Miha Kralj Date: Mon, 17 Apr 2023 16:54:23 -0700 Subject: [PATCH 3/4] Update 2MASlope_chart.cs --- Indicators/Charts/2MASlope_chart.cs | 22 +++++++++++++++------- Indicators/Charts/TrailingStop.cs | 1 - 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Indicators/Charts/2MASlope_chart.cs b/Indicators/Charts/2MASlope_chart.cs index 2c52110e..4f65c53e 100644 --- a/Indicators/Charts/2MASlope_chart.cs +++ b/Indicators/Charts/2MASlope_chart.cs @@ -50,6 +50,8 @@ public class MovingAverageSlope_chart : Indicator { private TSeries MA1, MA2; private LINREG_Series sMA1, sMA2; private CROSS_Series sig1, sig2; + + private bool inLong, inShort; /////// public MovingAverageSlope_chart() { @@ -240,31 +242,37 @@ public class MovingAverageSlope_chart : Indicator { this.LinesSeries[1].SetMarker(0,s2Color); if (sig1[^1].v > 0 || sig2[^1].v > 0) { - if (sMA1[^1].v >= 0 && sMA2[^1].v >= 0) + if (sMA1[^1].v >= 0 && sMA2[^1].v >= 0 && LongTrades) { + inLong = true; this.BeginCloud(0, 1, Color.FromArgb(127, Color.DarkGreen)); this.LinesSeries[(this.MA1[^1].v < this.MA2[^1].v)? 0 : 1 ].SetMarker(0, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.UpArrow)); } else { this.EndCloud(0, 1, Color.Empty); - this.LinesSeries[(this.MA1[^1].v < this.MA2[^1].v) ? 1 : 0].SetMarker(1, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.DownArrow)); + if (inShort) + { + this.LinesSeries[(this.MA1[^1].v < this.MA2[^1].v) ? 1 : 0].SetMarker(1, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.DownArrow)); + inShort = false; + } } - } if (sig1[^1].v < 0 || sig2[^1].v < 0) { - if (sMA1[^1].v <= 0 && sMA2[^1].v <= 0) + if (sMA1[^1].v <= 0 && sMA2[^1].v <= 0 && ShortTrades) { + inShort = true; this.BeginCloud(0, 1, Color.FromArgb(100, Color.Red)); this.LinesSeries[(this.MA1[^1].v > this.MA2[^1].v) ? 0 : 1].SetMarker(0, new IndicatorLineMarker(Color.OrangeRed, upperIcon: IndicatorLineMarkerIconType.UpArrow)); - } else { this.EndCloud(0, 1, Color.Empty); - this.LinesSeries[(this.MA1[^1].v > this.MA2[^1].v)?1:0].SetMarker(1, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.DownArrow)); + if (inLong) { + LinesSeries[(this.MA1[^1].v > this.MA2[^1].v)?1:0].SetMarker(1, new IndicatorLineMarker(Color.LimeGreen, bottomIcon: IndicatorLineMarkerIconType.DownArrow)); + inLong = false; + } } } - } public override void OnPaintChart(PaintChartEventArgs args) { base.OnPaintChart(args); diff --git a/Indicators/Charts/TrailingStop.cs b/Indicators/Charts/TrailingStop.cs index 3413ccb5..2f20542e 100644 --- a/Indicators/Charts/TrailingStop.cs +++ b/Indicators/Charts/TrailingStop.cs @@ -90,7 +90,6 @@ public class TrailingStop_chart : Indicator { this.SetValue(_ratchetL, lineIndex: 1); this.SetValue(_tslineS, lineIndex: 2); this.SetValue(_ratchetS, lineIndex: 3); - } public override void OnPaintChart(PaintChartEventArgs args) { From e1680e9d042325405ed81327d4af775ee68e8523 Mon Sep 17 00:00:00 2001 From: Miha Kralj Date: Mon, 24 Apr 2023 11:39:41 -0700 Subject: [PATCH 4/4] Update RSI_Series to check for period != 0 before calculating RSI --- Calculations/Basics/MAX_Series.cs | 25 - Calculations/Basics/MIDPOINT_Series.cs | 37 -- Calculations/Basics/MIN_Series.cs | 25 - Calculations/Basics/SUM_Series.cs | 35 -- Calculations/Basics/ZL_Series.cs | 34 -- Calculations/Calculations.csproj | 148 ++--- .../ClassStructures/Single_TBars_Abstract.cs | 2 +- .../Single_TSeries_Abstract.cs | 43 +- Calculations/ClassStructures/TBars.cs | 136 ----- Calculations/ClassStructures/TSeries.cs | 63 -- Calculations/Logic/EQUITY_Series.cs | 2 +- Calculations/Statistics/BIAS_Series.cs | 34 -- Calculations/Statistics/DECAY_Series.cs | 39 -- Calculations/Statistics/ENTROPY_Series.cs | 44 -- Calculations/Statistics/KURTOSIS_Series.cs | 57 -- Calculations/Statistics/MAD_Series.cs | 38 -- Calculations/Statistics/MAPE_Series.cs | 42 -- Calculations/Statistics/MEDIAN_Series.cs | 44 -- Calculations/Statistics/MSE_Series.cs | 33 -- Calculations/Statistics/SDEV_Series.cs | 39 -- Calculations/Statistics/SMAPE_Series.cs | 33 -- Calculations/Statistics/SSDEV_Series.cs | 39 -- Calculations/Statistics/SVAR_Series.cs | 38 -- Calculations/Statistics/VAR_Series.cs | 38 -- Calculations/Statistics/WMAPE_Series.cs | 40 -- Calculations/Statistics/ZSCORE_Series.cs | 46 -- Calculations/Trends/ALMA_Series.cs | 63 -- .../{Momentum => Trends}/CCI_Series.cs | 0 Calculations/Trends/DEMA_Series.cs | 72 --- Calculations/Trends/DWMA_Series.cs | 33 -- Calculations/Trends/EMA_Series.cs | 71 --- Calculations/Trends/FMA_Series.cs | 59 -- Calculations/Trends/HEMA_Series.cs | 57 -- Calculations/Trends/HMA_Series.cs | 119 ---- Calculations/Trends/KAMA_Series.cs | 64 -- Calculations/Trends/MAMA_Series.cs | 205 ++++--- Calculations/Trends/RMA_Series.cs | 56 -- Calculations/Trends/SMA_Series.cs | 44 -- Calculations/Trends/SMMA_Series.cs | 51 -- Calculations/Trends/T3_Series.cs | 100 ---- Calculations/Trends/TEMA_Series.cs | 70 --- Calculations/Trends/TRIMA_Series.cs | 43 -- Calculations/Trends/TRIX_Series.cs | 75 --- Calculations/Trends/WMA_Series.cs | 35 -- Calculations/Trends/ZLEMA_Series.cs | 62 -- Calculations/Volatility/ATRP_Series.cs | 2 +- Calculations/Volatility/CMO_Series.cs | 46 -- .../{Volume => Volatility}/OBV_Series.cs | 0 Calculations/Volatility/RSI_Series.cs | 78 --- Calculations/_Updated/ALMA_Series.cs | 107 ++++ Calculations/_Updated/BIAS_Series.cs | 75 +++ Calculations/_Updated/CMO_Series.cs | 92 +++ Calculations/_Updated/CUSUM_Series.cs | 74 +++ Calculations/_Updated/DECAY_Series.cs | 86 +++ Calculations/_Updated/DEMA_Series.cs | 131 +++++ Calculations/_Updated/DWMA_Series.cs | 126 ++++ Calculations/_Updated/EMA_Series.cs | 123 ++++ Calculations/_Updated/ENTROPY_Series.cs | 90 +++ Calculations/_Updated/FWMA_Series.cs | 100 ++++ Calculations/_Updated/HEMA_Series.cs | 116 ++++ Calculations/_Updated/HMA_Series.cs | 91 +++ .../{Trends => _Updated}/JMA_Series.cs | 86 ++- Calculations/_Updated/KAMA_Series.cs | 114 ++++ Calculations/_Updated/KURTOSIS_Series.cs | 99 ++++ Calculations/_Updated/MAD_Series.cs | 82 +++ Calculations/_Updated/MAPE_Series.cs | 88 +++ Calculations/_Updated/MAX_Series.cs | 71 +++ Calculations/_Updated/MEDIAN_Series.cs | 89 +++ Calculations/_Updated/MIDPOINT_Series.cs | 75 +++ Calculations/_Updated/MIN_Series.cs | 71 +++ Calculations/_Updated/MSE_Series.cs | 79 +++ Calculations/_Updated/RMA_Series.cs | 119 ++++ Calculations/_Updated/RSI_Series.cs | 123 ++++ Calculations/_Updated/SDEV_Series.cs | 85 +++ Calculations/_Updated/SMAPE_Series.cs | 80 +++ Calculations/_Updated/SMA_Series.cs | 99 ++++ Calculations/_Updated/SMMA_Series.cs | 96 +++ Calculations/_Updated/SSDEV_Series.cs | 85 +++ Calculations/_Updated/SVAR_Series.cs | 84 +++ Calculations/_Updated/T3_Series.cs | 164 ++++++ Calculations/_Updated/TBars.cs | 126 ++++ Calculations/_Updated/TEMA_Series.cs | 123 ++++ Calculations/_Updated/TRIMA_Series.cs | 87 +++ Calculations/_Updated/TRIX_Series.cs | 119 ++++ Calculations/_Updated/TSeries.cs | 85 +++ Calculations/_Updated/VAR_Series.cs | 84 +++ Calculations/_Updated/WMAPE_Series.cs | 85 +++ Calculations/_Updated/WMA_Series.cs | 107 ++++ Calculations/_Updated/ZLEMA_Series.cs | 97 ++++ Calculations/_Updated/ZL_Series.cs | 93 +++ Calculations/_Updated/ZSCORE_Series.cs | 91 +++ Calculations/_Updated/zMA_Series.cs | 72 +++ Indicators/Charts/2MACross_chart.cs | 12 +- Indicators/Charts/2MASlope_chart.cs | 18 +- Indicators/Charts/JMA_chart.cs | 4 +- Indicators/Indicators.csproj | 2 + Strategies/SimpleMACross1.cs | 2 +- Strategies/Strategies.csproj | 2 + Tests/Basic tests/Indicators.cs | 153 +++++ Tests/Basic tests/Oscillators.cs | 158 +++++ Tests/Basics/Abstract_Test.cs | 23 - Tests/Basics/TSeries_Test.cs | 61 -- Tests/MovingAvg/ALMA_Test.cs | 32 - Tests/MovingAvg/BBANDS_Test.cs | 56 -- Tests/MovingAvg/DEMA_Test.cs | 31 - Tests/MovingAvg/DWMA_Test.cs | 32 - Tests/MovingAvg/EMA_Test.cs | 32 - Tests/MovingAvg/FMA_Test.cs | 31 - Tests/MovingAvg/HEMA_Test.cs | 31 - Tests/MovingAvg/HMA_Test.cs | 31 - Tests/MovingAvg/JMA_Test.cs | 31 - Tests/MovingAvg/KAMA_Test.cs | 31 - Tests/MovingAvg/MACD_Test.cs | 31 - Tests/MovingAvg/RMA_Test.cs | 31 - Tests/MovingAvg/RSI_Test.cs | 31 - Tests/MovingAvg/SMA_Test.cs | 31 - Tests/MovingAvg/SMMA_Test.cs | 31 - Tests/MovingAvg/TEMA_Test.cs | 31 - Tests/MovingAvg/WMA_Test.cs | 31 - Tests/MovingAvg/ZLEMA_Test.cs | 31 - Tests/{Basics => Pairs}/ADD_Test.cs | 2 +- Tests/{Basics => Pairs}/DIV_Test.cs | 2 +- Tests/{Basics => Pairs}/MUL_Test.cs | 2 +- Tests/{Basics => Pairs}/SUB_Test.cs | 2 +- Tests/{Basics => Pairs}/TBars_Test.cs | 224 +++---- Tests/Series/Update.cs | 545 ------------------ Tests/Statistics/BIAS_Test.cs | 31 - Tests/Statistics/ENTP_Test.cs | 31 - Tests/Statistics/KURT_Test.cs | 31 - Tests/Statistics/LINREG_Test.cs | 31 - Tests/Statistics/MAD_Test.cs | 31 - Tests/Statistics/MAPE_Test.cs | 31 - Tests/Statistics/MAX_Test.cs | 31 - Tests/Statistics/MED_Test.cs | 31 - Tests/Statistics/MIN_Test.cs | 31 - Tests/Statistics/MSE_Test.cs | 31 - Tests/Statistics/PSDEV_Test.cs | 31 - Tests/Statistics/PVAR_Test .cs | 31 - Tests/Statistics/SDEV_Test .cs | 31 - Tests/Statistics/SMAPE_Test.cs | 31 - Tests/Statistics/VAR_Test.cs | 31 - Tests/Statistics/WMAPE_Test.cs | 31 - Tests/Tests.csproj | 7 +- Tests/Validations/Trends/TA_LIB.cs | 2 +- Tests/Validations/Trends/Tulip.cs | 2 +- 145 files changed, 4826 insertions(+), 4207 deletions(-) delete mode 100644 Calculations/Basics/MAX_Series.cs delete mode 100644 Calculations/Basics/MIDPOINT_Series.cs delete mode 100644 Calculations/Basics/MIN_Series.cs delete mode 100644 Calculations/Basics/SUM_Series.cs delete mode 100644 Calculations/Basics/ZL_Series.cs delete mode 100644 Calculations/ClassStructures/TBars.cs delete mode 100644 Calculations/ClassStructures/TSeries.cs delete mode 100644 Calculations/Statistics/BIAS_Series.cs delete mode 100644 Calculations/Statistics/DECAY_Series.cs delete mode 100644 Calculations/Statistics/ENTROPY_Series.cs delete mode 100644 Calculations/Statistics/KURTOSIS_Series.cs delete mode 100644 Calculations/Statistics/MAD_Series.cs delete mode 100644 Calculations/Statistics/MAPE_Series.cs delete mode 100644 Calculations/Statistics/MEDIAN_Series.cs delete mode 100644 Calculations/Statistics/MSE_Series.cs delete mode 100644 Calculations/Statistics/SDEV_Series.cs delete mode 100644 Calculations/Statistics/SMAPE_Series.cs delete mode 100644 Calculations/Statistics/SSDEV_Series.cs delete mode 100644 Calculations/Statistics/SVAR_Series.cs delete mode 100644 Calculations/Statistics/VAR_Series.cs delete mode 100644 Calculations/Statistics/WMAPE_Series.cs delete mode 100644 Calculations/Statistics/ZSCORE_Series.cs delete mode 100644 Calculations/Trends/ALMA_Series.cs rename Calculations/{Momentum => Trends}/CCI_Series.cs (100%) delete mode 100644 Calculations/Trends/DEMA_Series.cs delete mode 100644 Calculations/Trends/DWMA_Series.cs delete mode 100644 Calculations/Trends/EMA_Series.cs delete mode 100644 Calculations/Trends/FMA_Series.cs delete mode 100644 Calculations/Trends/HEMA_Series.cs delete mode 100644 Calculations/Trends/HMA_Series.cs delete mode 100644 Calculations/Trends/KAMA_Series.cs delete mode 100644 Calculations/Trends/RMA_Series.cs delete mode 100644 Calculations/Trends/SMA_Series.cs delete mode 100644 Calculations/Trends/SMMA_Series.cs delete mode 100644 Calculations/Trends/T3_Series.cs delete mode 100644 Calculations/Trends/TEMA_Series.cs delete mode 100644 Calculations/Trends/TRIMA_Series.cs delete mode 100644 Calculations/Trends/TRIX_Series.cs delete mode 100644 Calculations/Trends/WMA_Series.cs delete mode 100644 Calculations/Trends/ZLEMA_Series.cs delete mode 100644 Calculations/Volatility/CMO_Series.cs rename Calculations/{Volume => Volatility}/OBV_Series.cs (100%) delete mode 100644 Calculations/Volatility/RSI_Series.cs create mode 100644 Calculations/_Updated/ALMA_Series.cs create mode 100644 Calculations/_Updated/BIAS_Series.cs create mode 100644 Calculations/_Updated/CMO_Series.cs create mode 100644 Calculations/_Updated/CUSUM_Series.cs create mode 100644 Calculations/_Updated/DECAY_Series.cs create mode 100644 Calculations/_Updated/DEMA_Series.cs create mode 100644 Calculations/_Updated/DWMA_Series.cs create mode 100644 Calculations/_Updated/EMA_Series.cs create mode 100644 Calculations/_Updated/ENTROPY_Series.cs create mode 100644 Calculations/_Updated/FWMA_Series.cs create mode 100644 Calculations/_Updated/HEMA_Series.cs create mode 100644 Calculations/_Updated/HMA_Series.cs rename Calculations/{Trends => _Updated}/JMA_Series.cs (54%) create mode 100644 Calculations/_Updated/KAMA_Series.cs create mode 100644 Calculations/_Updated/KURTOSIS_Series.cs create mode 100644 Calculations/_Updated/MAD_Series.cs create mode 100644 Calculations/_Updated/MAPE_Series.cs create mode 100644 Calculations/_Updated/MAX_Series.cs create mode 100644 Calculations/_Updated/MEDIAN_Series.cs create mode 100644 Calculations/_Updated/MIDPOINT_Series.cs create mode 100644 Calculations/_Updated/MIN_Series.cs create mode 100644 Calculations/_Updated/MSE_Series.cs create mode 100644 Calculations/_Updated/RMA_Series.cs create mode 100644 Calculations/_Updated/RSI_Series.cs create mode 100644 Calculations/_Updated/SDEV_Series.cs create mode 100644 Calculations/_Updated/SMAPE_Series.cs create mode 100644 Calculations/_Updated/SMA_Series.cs create mode 100644 Calculations/_Updated/SMMA_Series.cs create mode 100644 Calculations/_Updated/SSDEV_Series.cs create mode 100644 Calculations/_Updated/SVAR_Series.cs create mode 100644 Calculations/_Updated/T3_Series.cs create mode 100644 Calculations/_Updated/TBars.cs create mode 100644 Calculations/_Updated/TEMA_Series.cs create mode 100644 Calculations/_Updated/TRIMA_Series.cs create mode 100644 Calculations/_Updated/TRIX_Series.cs create mode 100644 Calculations/_Updated/TSeries.cs create mode 100644 Calculations/_Updated/VAR_Series.cs create mode 100644 Calculations/_Updated/WMAPE_Series.cs create mode 100644 Calculations/_Updated/WMA_Series.cs create mode 100644 Calculations/_Updated/ZLEMA_Series.cs create mode 100644 Calculations/_Updated/ZL_Series.cs create mode 100644 Calculations/_Updated/ZSCORE_Series.cs create mode 100644 Calculations/_Updated/zMA_Series.cs create mode 100644 Tests/Basic tests/Indicators.cs create mode 100644 Tests/Basic tests/Oscillators.cs delete mode 100644 Tests/Basics/Abstract_Test.cs delete mode 100644 Tests/Basics/TSeries_Test.cs delete mode 100644 Tests/MovingAvg/ALMA_Test.cs delete mode 100644 Tests/MovingAvg/BBANDS_Test.cs delete mode 100644 Tests/MovingAvg/DEMA_Test.cs delete mode 100644 Tests/MovingAvg/DWMA_Test.cs delete mode 100644 Tests/MovingAvg/EMA_Test.cs delete mode 100644 Tests/MovingAvg/FMA_Test.cs delete mode 100644 Tests/MovingAvg/HEMA_Test.cs delete mode 100644 Tests/MovingAvg/HMA_Test.cs delete mode 100644 Tests/MovingAvg/JMA_Test.cs delete mode 100644 Tests/MovingAvg/KAMA_Test.cs delete mode 100644 Tests/MovingAvg/MACD_Test.cs delete mode 100644 Tests/MovingAvg/RMA_Test.cs delete mode 100644 Tests/MovingAvg/RSI_Test.cs delete mode 100644 Tests/MovingAvg/SMA_Test.cs delete mode 100644 Tests/MovingAvg/SMMA_Test.cs delete mode 100644 Tests/MovingAvg/TEMA_Test.cs delete mode 100644 Tests/MovingAvg/WMA_Test.cs delete mode 100644 Tests/MovingAvg/ZLEMA_Test.cs rename Tests/{Basics => Pairs}/ADD_Test.cs (98%) rename Tests/{Basics => Pairs}/DIV_Test.cs (98%) rename Tests/{Basics => Pairs}/MUL_Test.cs (98%) rename Tests/{Basics => Pairs}/SUB_Test.cs (98%) rename Tests/{Basics => Pairs}/TBars_Test.cs (95%) delete mode 100644 Tests/Series/Update.cs delete mode 100644 Tests/Statistics/BIAS_Test.cs delete mode 100644 Tests/Statistics/ENTP_Test.cs delete mode 100644 Tests/Statistics/KURT_Test.cs delete mode 100644 Tests/Statistics/LINREG_Test.cs delete mode 100644 Tests/Statistics/MAD_Test.cs delete mode 100644 Tests/Statistics/MAPE_Test.cs delete mode 100644 Tests/Statistics/MAX_Test.cs delete mode 100644 Tests/Statistics/MED_Test.cs delete mode 100644 Tests/Statistics/MIN_Test.cs delete mode 100644 Tests/Statistics/MSE_Test.cs delete mode 100644 Tests/Statistics/PSDEV_Test.cs delete mode 100644 Tests/Statistics/PVAR_Test .cs delete mode 100644 Tests/Statistics/SDEV_Test .cs delete mode 100644 Tests/Statistics/SMAPE_Test.cs delete mode 100644 Tests/Statistics/VAR_Test.cs delete mode 100644 Tests/Statistics/WMAPE_Test.cs diff --git a/Calculations/Basics/MAX_Series.cs b/Calculations/Basics/MAX_Series.cs deleted file mode 100644 index 109461a9..00000000 --- a/Calculations/Basics/MAX_Series.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 System.Collections.Generic.List _buffer = new(); - - public override void Add((DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _max = _buffer.Max(); - - base.Add((TValue.t, _max), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Basics/MIDPOINT_Series.cs b/Calculations/Basics/MIDPOINT_Series.cs deleted file mode 100644 index d96a39a6..00000000 --- a/Calculations/Basics/MIDPOINT_Series.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -MIDPOINT: Midpoint value (max+min)/2 in the given period in the series. - If period = 0 => period = full length of the series - -Sources: - https://thefaqblog.com/what-is-the-midpoint-in-statistics/ - - */ - -public class MIDPOINT_Series : Single_TSeries_Indicator -{ - public MIDPOINT_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) - { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - double _max = TValue.v; - double _min = TValue.v; - for (int i = 0; i < this._buffer.Count; i++) - { - _max = Math.Max(this._buffer[i], _max); - _min = Math.Min(this._buffer[i], _min); - } - double _mid = (_max + _min) * 0.5; - - base.Add((TValue.t, _mid), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Basics/MIN_Series.cs b/Calculations/Basics/MIN_Series.cs deleted file mode 100644 index e41a0ba4..00000000 --- a/Calculations/Basics/MIN_Series.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 -{ - public MIN_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - double _min = _buffer.Min(); - base.Add((TValue.t, _min), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Basics/SUM_Series.cs b/Calculations/Basics/SUM_Series.cs deleted file mode 100644 index bb98134d..00000000 --- a/Calculations/Basics/SUM_Series.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -SUM: Cumulative Sum (aka Running Total) - SUM across a period provides a rolling sum of all values across the period. - If SUM values would be divided with period, the output would be SMA() - -Sources: - https://en.wikipedia.org/wiki/CUSUM - - */ - -public class SUM_Series : Single_TSeries_Indicator -{ - public SUM_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - if (update) { _buffer[_buffer.Count - 1] = TValue.v; } - else { _buffer.Add(TValue.v); } - if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); } - - double _sum = 0; - for (int i = 0; i < _buffer.Count; i++) { _sum += _buffer[i]; } - - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _sum); - - base.Add(result, update); - } -} diff --git a/Calculations/Basics/ZL_Series.cs b/Calculations/Basics/ZL_Series.cs deleted file mode 100644 index 0a85f65b..00000000 --- a/Calculations/Basics/ZL_Series.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -ZL: Zero Lag - Data is de-lagged by removing the data from “lag” days ago, thus removing - (or attempting to) the cumulative effect of the moving average. - -Calculation: - Lag = (Period-1)/2 - ZL = Data + (Data - Data(Lag days ago) ) - -Sources: - https://mudrex.com/blog/zero-lag-ema-trading-strategy/ - - */ - -public class ZL_Series : Single_TSeries_Indicator -{ - public ZL_Series(TSeries source, int period, bool useNaN = false) : base(source, period:period, useNaN:useNaN) { - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((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); - - 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/Calculations/Calculations.csproj b/Calculations/Calculations.csproj index 4140e36e..466a0ced 100644 --- a/Calculations/Calculations.csproj +++ b/Calculations/Calculations.csproj @@ -1,74 +1,82 @@ - - - QuanTAlib - 0.2.0 - Library of TA Calculations, Charts and Strategies for Quantower - Quantitative Technical Analysis Library in C# for Quantower - git - https://github.com/mihakralj/QuanTAlib - true - Miha Kralj - Miha Kralj - readme.md - net8.0;net7.0;net6.0 - disable - preview - disable - true - en-US - QuanTAlib - QuanTAlib - True - AnyCPU - False - embedded - True - True - + + + + QuanTAlib + 0.2.0 + Library of TA Calculations, Charts and Strategies for Quantower + Quantitative Technical Analysis Library in C# for Quantower + git + https://github.com/mihakralj/QuanTAlib + true + Miha Kralj + Miha Kralj + readme.md + net8.0;net7.0;net6.0 + disable + preview + disable + true + en-US + QuanTAlib + QuanTAlib + True + AnyCPU + False + embedded + True + True + Indicators;Stock;Market;Technical;Analysis;Algorithmic;Trading;Trade;Trend;Momentum;Finance;Algorithm;Algo; AlgoTrading;Financial;Strategy;Chart;Charting;Oscillator;Overlay;Equity;Bitcoin;Crypto;Cryptocurrency;Forex; Quantitative;Historical;Quotes; - - Apache-2.0 - - 0.2.1.0 - 0.2.1.0 - 0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d - NETSDK1057 - - - full - True - 7 - True - anycpu - - - - True - 7 - True - anycpu - - - QuanTAlib2.png - https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png - True - ..\.sonarlint\mihakralj_quantalibcsharp.ruleset - 0.2.1-dev.2 - - - - - - - True - - - - True - False - - - + + Apache-2.0 + + + 0.2.1.0 + 0.2.1.0 + 0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d + NETSDK1057 + IDE1006 + true + $(NoWarn);NETSDK1057 + + + full + True + 7 + True + anycpu + + + + + True + 7 + True + anycpu + + + QuanTAlib2.png + https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png + True + ..\.sonarlint\mihakralj_quantalibcsharp.ruleset + 0.2.1-dev.2 + + + + + + + True + + + + + True + False + + + + \ No newline at end of file diff --git a/Calculations/ClassStructures/Single_TBars_Abstract.cs b/Calculations/ClassStructures/Single_TBars_Abstract.cs index 4d5e3170..1d3c8ac8 100644 --- a/Calculations/ClassStructures/Single_TBars_Abstract.cs +++ b/Calculations/ClassStructures/Single_TBars_Abstract.cs @@ -44,7 +44,7 @@ public abstract class Single_TBars_Indicator : TSeries // 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 virtual new 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); diff --git a/Calculations/ClassStructures/Single_TSeries_Abstract.cs b/Calculations/ClassStructures/Single_TSeries_Abstract.cs index d52ad80d..ca8d3d89 100644 --- a/Calculations/ClassStructures/Single_TSeries_Abstract.cs +++ b/Calculations/ClassStructures/Single_TSeries_Abstract.cs @@ -23,29 +23,32 @@ public abstract class Single_TSeries_Indicator : TSeries protected readonly TSeries _data; protected int _p; - // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN) - protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN) { - _data = source; - _period = period; - _p = _period; - _NaN = useNaN; - _data.Pub += Sub; - } + // Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN) + protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN) + { + _data = source; + _period = period; + _p = _period; + _NaN = useNaN; + _data.Pub += Sub; + } - // overridable Add() method to add/update a single item at the end of the list + // overridable Add() method to add/update a single item at the end of the list - public virtual void Add((DateTime t, double v) TValue, bool update, bool useNaN) { - if (_period == 0) { _p = Length; } - var res = (TValue.t, Count < _p - 1 && _NaN ? double.NaN : TValue.v); - base.Add(res, update); - } - public new virtual void Add((DateTime t, double v) TValue, bool update) => base.Add(TValue, update); + public virtual void Add((DateTime t, double v) TValue, bool update, bool useNaN) + { + if (_period == 0) { _p = Length; } + var res = (TValue.t, Count < _p - 1 && _NaN ? double.NaN : TValue.v); + base.Add(res, update); + } + public new virtual void Add((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) { - foreach (var item in data) { Add(TValue: item, update: false); } - } - public new void Add((System.DateTime t, double v) TValue) => this.Add(TValue: TValue, update: false); + // potentially overridable Add() method for the whole series (could be replaced with faster bulk algo) + public virtual new void Add(TSeries data) + { + foreach (var item in data) { Add(TValue: item, 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); diff --git a/Calculations/ClassStructures/TBars.cs b/Calculations/ClassStructures/TBars.cs deleted file mode 100644 index 562cc968..00000000 --- a/Calculations/ClassStructures/TBars.cs +++ /dev/null @@ -1,136 +0,0 @@ -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(); - private readonly TSeries _high = new(); - private readonly TSeries _low = new(); - private readonly TSeries _close = new(); - private readonly TSeries _volume = new(); - private readonly TSeries _hl2 = new(); - private readonly TSeries _oc2 = new(); - private readonly TSeries _ohl3 = new(); - private readonly TSeries _hlc3 = new(); - private readonly TSeries _ohlc4 = new(); - private readonly TSeries _hlcc4 = new(); - - public TSeries Open => this._open; - public TSeries High => this._high; - public TSeries Low => this._low; - public TSeries Close => this._close; - public TSeries Volume => this._volume; - public TSeries HL2 => this._hl2; - public TSeries OC2 => this._oc2; - public TSeries OHL3 => this._ohl3; - public TSeries HLC3 => this._hlc3; - public TSeries OHLC4 => this._ohlc4; - public TSeries HLCC4 => this._hlcc4; - - public TBars Tail(int count = 10) - { - TBars outBars = new(); - if (count > this.Count) { count = this.Count; } - for (int i = this.Count - count; i < this.Count; i++) { outBars.Add(this[i]); } - return outBars; - } - public TSeries Select(int source) - { - return source switch - { - 0 => _open, - 1 => _high, - 2 => _low, - 3 => _close, - 4 => _hl2, - 5 => _oc2, - 6 => _ohl3, - 7 => _hlc3, - 8 => _ohlc4, - _ => _hlcc4, - }; - } - public static string SelectStr(int source) - { - return source switch - { - 0 => "Open", - 1 => "High", - 2 => "Low", - 3 => "Close", - 4 => "HL2", - 5 => "OC2", - 6 => "OHL3", - 7 => "HLC3", - 8 => "OHLC4", - _ => "HLCC4", - }; - } - - public 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); - - public void Add(DateTime t, decimal o, decimal h, decimal l, decimal c, decimal v, bool update = false) - => Add(t, (double)o, (double)h, (double)l, (double)c, (double)v, update); - - public void Add(DateTime t, double o, double h, double l, double c, double v, bool update = false) - { - if (update) { - this[this.Count - 1] = (t, o, h, l, c, v); - } - else { - base.Add((t, o, h, l, c, v)); - } - _open.Add((t, o),update); - _high.Add((t, h), update); - _low.Add((t, l), update); - _close.Add((t, c), update); - _volume.Add((t, v), update); - _hl2.Add((t, (h + l) * 0.5), update); - _oc2.Add((t, (o + c) * 0.5), update); - _ohl3.Add((t, (o + h + l) * 0.333333333333333), update); - _hlc3.Add((t, (h + l + c) * 0.333333333333333), update); - _ohlc4.Add((t, (o + h + l + c) * 0.25), update); - _hlcc4.Add((t, (h + l + c + c) * 0.25), update); - - this.OnEvent(update); - } - - // delegate used by event handler + event handler (Pub == publisher) - public delegate void NewDataEventHandler(object source, TSeriesEventArgs args); - public event NewDataEventHandler Pub; - - // Broadcast handler - only to valid targets - protected virtual void OnEvent(bool update = false) - { - if (Pub != null && Pub.Target != this) - { - Pub(this, new TSeriesEventArgs { update = update }); - } - } - - public void Sub(object source, TSeriesEventArgs e) - { - TBars ss = (TBars)source; - if (ss.Count > 1) - { - for (int i = 0; i < ss.Count; i++) - { - this.Add(ss[i]); - } - } - else - { - this.Add(ss[ss.Count - 1], e.update); - } - } -} diff --git a/Calculations/ClassStructures/TSeries.cs b/Calculations/ClassStructures/TSeries.cs deleted file mode 100644 index eafec24d..00000000 --- a/Calculations/ClassStructures/TSeries.cs +++ /dev/null @@ -1,63 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Data; -using System.Linq; - -/* -TSeries is the cornerstone of all QuanTAlib classes. - TSeries is a single List of tuples (time, value) and contains several operators, casts, overloads - and other helpers that simplify usage of library. - Think of TSeries as an equivalent of Numpy array. - - - includes Length property (to mimic array's method) - - includes publishing and subscribing methods that attach to events - - */ - - -public class TSeriesEventArgs : EventArgs{ - public bool update { get; set; } -} - -public class TSeries : List<(DateTime t, double v)> { - - public static implicit operator (DateTime t, double v)(TSeries l) => l[^1]; - public static implicit operator double(TSeries l) => l[^1].v; - public static implicit operator DateTime(TSeries l) => l[^1].t; - public List t => this.Select(item => item.t).ToList(); - public List v => this.Select(item => item.v).ToList(); - public int Length => this.Count; - - public TSeries Tail(int count = 10) { - var tailSeries = new TSeries(); - tailSeries.AddRange(this.Skip(Math.Max(0, this.Count - count)).Take(count)); - return tailSeries; - } - public (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { - if (update) { this[^1] = TValue; } - else { base.Add(TValue); } - OnEvent(update); - return TValue; - } - - public void Add(DateTime t, double v, bool update = false) => this.Add((t, v), update); - public void Add(double v, bool update = false) => this.Add((DateTime.Now, v), update); - protected virtual void OnEvent(bool update = false) { - Pub?.Invoke(this, new TSeriesEventArgs { update = update }); - } - - public delegate void NewDataEventHandler(object source, TSeriesEventArgs args); - public event NewDataEventHandler Pub; - - public void Sub(object source, TSeriesEventArgs e) { - TSeries ss = (TSeries)source; - if (ss.Count > 0) { - this.AddRange(ss); - } - else { - this.Add(ss[^1], e.update); - } - } -} diff --git a/Calculations/Logic/EQUITY_Series.cs b/Calculations/Logic/EQUITY_Series.cs index 1257352d..50313152 100644 --- a/Calculations/Logic/EQUITY_Series.cs +++ b/Calculations/Logic/EQUITY_Series.cs @@ -81,7 +81,7 @@ public class EQUITY_Series : Single_TSeries_Indicator { //Console.WriteLine($"{TValue.v,3}\t {(_inmarket)} : {_cash,10:f2} + {_units*_price[this.Count-1].v,7:f2} = {_equity-_capital:f2}"); } - inmarket.Add(TValue.t, (double)_inmarket); + inmarket.Add((TValue.t, (double)_inmarket)); base.Add((TValue.t, _equity), update, _NaN); } } \ No newline at end of file diff --git a/Calculations/Statistics/BIAS_Series.cs b/Calculations/Statistics/BIAS_Series.cs deleted file mode 100644 index 7440a5f3..00000000 --- a/Calculations/Statistics/BIAS_Series.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 - = (close / SMA) - 1 - -Sources: - https://en.wikipedia.org/wiki/Bias_of_an_estimator - - */ - -public class BIAS_Series : Single_TSeries_Indicator -{ - public BIAS_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - double _sma = _buffer.Average(); - double _bias = (_buffer[_buffer.Count - 1] / ((_sma != 0) ? _sma : 1)) - 1; - - base.Add((TValue.t, _bias), update, _NaN); - } -} diff --git a/Calculations/Statistics/DECAY_Series.cs b/Calculations/Statistics/DECAY_Series.cs deleted file mode 100644 index 2084c95a..00000000 --- a/Calculations/Statistics/DECAY_Series.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Collections.Generic; - - -/* -DECAY: - Linear decay can be modeled by a straight line with a negative slope of 1/period. - The value decreases in a straight line from the last maximum to 0. - Decay = Last Max - distance/period - - Exponential decay is modeled as an exponential curve with diminishing factor of - 1-1/p - - */ - -public class DECAY_Series : Single_TSeries_Indicator { - private readonly bool _exp; - private double _pdecay, _ppdecay; - private readonly double _dfactor; - - public DECAY_Series(TSeries source, int period = 10, bool exponential= false, bool useNaN = false) : base(source, period, false) { - _exp = exponential; - _dfactor = (_exp)? 1.0 - 1.0 / (double)_p : 1/(double)_p; - _pdecay = _ppdecay = 0; - if (source.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - if (update) { _pdecay = _ppdecay; } - else { _ppdecay = _pdecay; } - - if (this.Count == 0) { _pdecay = TValue.v; } - double _decay = Math.Max(TValue.v, Math.Max((_exp)?_pdecay*_dfactor:_pdecay-_dfactor, 0)); - _pdecay = _decay; - - base.Add((TValue.t, _decay), update, _NaN); - } -} diff --git a/Calculations/Statistics/ENTROPY_Series.cs b/Calculations/Statistics/ENTROPY_Series.cs deleted file mode 100644 index f27ea6c7..00000000 --- a/Calculations/Statistics/ENTROPY_Series.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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) - ENTP = Σ(-P * Log(P) / Log(base)) - -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 - - */ - -public class ENTROPY_Series : Single_TSeries_Indicator -{ - public ENTROPY_Series(TSeries source, int period, double logbase = 2.0, bool useNaN = false) : base(source, period, useNaN) - { - this._logbase = logbase; - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly double _logbase; - private readonly System.Collections.Generic.List _buffer = new(); - private readonly System.Collections.Generic.List _buff2 = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sum = _buffer.Sum(); - - double _pp = this._buffer[this._buffer.Count - 1] / _sum; - double _ppp = -_pp * Math.Log(_pp) / Math.Log(this._logbase); - - Add_Replace_Trim(_buff2, _ppp, _p, update); - double _entp = _buff2.Sum(); - - base.Add((TValue.t, _entp), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/KURTOSIS_Series.cs b/Calculations/Statistics/KURTOSIS_Series.cs deleted file mode 100644 index ae1c93b2..00000000 --- a/Calculations/Statistics/KURTOSIS_Series.cs +++ /dev/null @@ -1,57 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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. - - The normal curve is called Mesokurtic curve. If the curve of a distribution is - more outlier prone (or heavier-tailed) than a normal or mesokurtic curve then - it is referred to as a Leptokurtic curve. If a curve is less outlier prone (or - lighter-tailed) than a normal curve, it is called as a platykurtic curve. - -Calculation: - sum4 = Σ(close-SMA)^4 - sum2 = (Σ(close-SMA)^2)^2 - KURT = length * (sum4/sum2) - -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/ - - */ - -public class KURTOSIS_Series : Single_TSeries_Indicator -{ - public KURTOSIS_Series(TSeries source, int period, double logbase = 2.0, bool useNaN = false) : base(source, period, useNaN) - { - this._logbase = logbase; - if (base._data.Count > 0) { base.Add(base._data); } - } - protected double _logbase; - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _n = this._buffer.Count; - double _avg = _buffer.Average(); - - double _s2 = 0; - double _s4 = 0; - for (int i = 0; i < this._buffer.Count; i++) - { - _s2 += (_buffer[i] - _avg) * (_buffer[i] - _avg); - _s4 += (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg); - } - - 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; - - var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? Double.NaN : _kurt); - base.Add(result, update); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/MAD_Series.cs b/Calculations/Statistics/MAD_Series.cs deleted file mode 100644 index 8a032e4a..00000000 --- a/Calculations/Statistics/MAD_Series.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 - -Sources: - https://en.wikipedia.org/wiki/Average_absolute_deviation - - */ - -public class MAD_Series : Single_TSeries_Indicator -{ - public MAD_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - double _sma = _buffer.Average(); - - double _mad = 0; - for (int i = 0; i < _buffer.Count; i++) { _mad += Math.Abs(_buffer[i] - _sma); } - _mad /= this._buffer.Count; - - base.Add((TValue.t, _mad), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/MAPE_Series.cs b/Calculations/Statistics/MAPE_Series.cs deleted file mode 100644 index ca737cf1..00000000 --- a/Calculations/Statistics/MAPE_Series.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -MAPE: Mean Absolute Percentage Error - Measures the size of the error in percentage terms - -Calculation: - MAPE = Σ(|close – SMA| / |close|) / n - -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 - - */ - -public class MAPE_Series : Single_TSeries_Indicator -{ - public MAPE_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _mape = 0; - for (int i = 0; i < _buffer.Count; i++) { - _mape += (_buffer[i] != 0) ? Math.Abs(_buffer[i] - _sma) / Math.Abs(_buffer[i]) : double.PositiveInfinity; - } - _mape /= (_buffer.Count>0) ? _buffer.Count : 1; - - base.Add((TValue.t, _mape), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/MEDIAN_Series.cs b/Calculations/Statistics/MEDIAN_Series.cs deleted file mode 100644 index 0bbd6948..00000000 --- a/Calculations/Statistics/MEDIAN_Series.cs +++ /dev/null @@ -1,44 +0,0 @@ -namespace QuanTAlib; -using System; -using static System.Net.Mime.MediaTypeNames; - -/* -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. - - 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 - -Sources: - https://corporatefinanceinstitute.com/resources/knowledge/other/median/ - https://en.wikipedia.org/wiki/Median - - */ - -public class MEDIAN_Series : Single_TSeries_Indicator -{ - public MEDIAN_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - System.Collections.Generic.List _s = new(this._buffer); - _s.Sort(); - int _p1 = _s.Count / 2; - int _p2 = Math.Max(0, (_s.Count / 2) - 1); - double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2; - - base.Add((TValue.t, _med), update, _NaN); - } -} diff --git a/Calculations/Statistics/MSE_Series.cs b/Calculations/Statistics/MSE_Series.cs deleted file mode 100644 index 1dcdd6a9..00000000 --- a/Calculations/Statistics/MSE_Series.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 - - */ - -public class MSE_Series : Single_TSeries_Indicator -{ - public MSE_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _mse = 0; - for (int i = 0; i < _buffer.Count; i++) { _mse += (_buffer[i] - _sma) * (_buffer[i] - _sma); } - _mse /= this._buffer.Count; - - base.Add((TValue.t, _mse), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/SDEV_Series.cs b/Calculations/Statistics/SDEV_Series.cs deleted file mode 100644 index b85c3a16..00000000 --- a/Calculations/Statistics/SDEV_Series.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -SDEV: 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 - -Remark: - SDEV (Population Standard Deviation) is also known as a biased/uncorrected Standard Deviation. - For unbiased version that uses Bessel's correction, use SDEV instead. - - */ - -public class SDEV_Series : Single_TSeries_Indicator -{ - public SDEV_Series(TSeries source, int period=0, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _pvar = 0; - for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } - _pvar /= this._buffer.Count; - double _psdev = Math.Sqrt(_pvar); - - base.Add((TValue.t, _psdev), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/SMAPE_Series.cs b/Calculations/Statistics/SMAPE_Series.cs deleted file mode 100644 index dc0eaaa5..00000000 --- a/Calculations/Statistics/SMAPE_Series.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 - - */ - -public class SMAPE_Series : Single_TSeries_Indicator -{ - public SMAPE_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _smape = 0; - for (int i = 0; i < _buffer.Count; i++) { _smape += Math.Abs(_buffer[i] - _sma) / (Math.Abs(_buffer[i]) + Math.Abs(_sma)); } - _smape /= this._buffer.Count; - - base.Add((TValue.t, _smape), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/SSDEV_Series.cs b/Calculations/Statistics/SSDEV_Series.cs deleted file mode 100644 index ab882476..00000000 --- a/Calculations/Statistics/SSDEV_Series.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -SSDEV: (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 - - */ - -public class SSDEV_Series : Single_TSeries_Indicator -{ - public SSDEV_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _svar = 0; - for (int i = 0; i < this._buffer.Count; i++) { _svar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } - _svar /= (_buffer.Count > 1) ? _buffer.Count - 1 : 1; // Bessel's correction - double _ssdev = Math.Sqrt(_svar); - - base.Add((TValue.t, _ssdev), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/SVAR_Series.cs b/Calculations/Statistics/SVAR_Series.cs deleted file mode 100644 index a83d5deb..00000000 --- a/Calculations/Statistics/SVAR_Series.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -SVAR: 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 - Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction - -Remark: - SVAR is also known as the Unbiased Sample Variance, while VAR (Population Variance) is known as - the Biased Sample Variance. - - */ - -public class SVAR_Series : Single_TSeries_Indicator -{ - public SVAR_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _svar = 0; - for (int i = 0; i < this._buffer.Count; i++) { _svar += (this._buffer[i] - _sma) * (this._buffer[i] - _sma); } - _svar /= (this._buffer.Count > 1) ? this._buffer.Count - 1 : 1; // Bessel's correction - - base.Add((TValue.t, _svar), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/VAR_Series.cs b/Calculations/Statistics/VAR_Series.cs deleted file mode 100644 index 447ae16f..00000000 --- a/Calculations/Statistics/VAR_Series.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -VAR: Population Variance - Population variance without Bessel's correction - -Sources: - https://en.wikipedia.org/wiki/Variance - Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction - -Remark: - VAR (Population Variance) is also known as a biased Sample Variance. For unbiased - sample variance use SVAR instead. - - */ - -public class VAR_Series : Single_TSeries_Indicator -{ - public VAR_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _pvar = 0; - for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } - _pvar /= this._buffer.Count; - - base.Add((TValue.t, _pvar), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/WMAPE_Series.cs b/Calculations/Statistics/WMAPE_Series.cs deleted file mode 100644 index ff2a112a..00000000 --- a/Calculations/Statistics/WMAPE_Series.cs +++ /dev/null @@ -1,40 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -WMAPE: Weighted Mean Absolute Percentage Error - Measures the size of the error in percentage terms. Improves problems with MAPE - when there are zero or close-to-zero values because there would be a division by zero - or values of MAPE tending to infinity. - -Sources: - https://en.wikipedia.org/wiki/WMAPE - - */ - -public class WMAPE_Series : Single_TSeries_Indicator -{ - public WMAPE_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _div = 0; - double _wmape = 0; - for (int i = 0; i < _buffer.Count; i++) - { - _wmape += Math.Abs(_buffer[i] - _sma); - _div += Math.Abs(_buffer[i]); - } - _wmape = (_div!=0) ? _wmape/_div : double.PositiveInfinity; - - base.Add((TValue.t, _wmape), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Statistics/ZSCORE_Series.cs b/Calculations/Statistics/ZSCORE_Series.cs deleted file mode 100644 index fbaf02b9..00000000 --- a/Calculations/Statistics/ZSCORE_Series.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -ZSCORE: number of standard deviations from SMA - Z-score describes a value's relationship to the mean of a series, as measured in - terms of standard deviations from the mean. If a Z-score is 0, it indicates that - the data point's score is identical to the mean score. A Z-score of 1.0 would - indicate a value that is one standard deviation from the mean. Z-scores may be - positive or negative, with a positive value indicating the score is above the - mean and a negative score indicating it is below the mean. - -Sources: - https://en.wikipedia.org/wiki/Z-score - https://www.investopedia.com/terms/z/zscore.asp - -Calculation: - std = std * STDEV(close, length) - mean = SMA(close, length) - ZSCORE = (close - mean) / std - - */ - -public class ZSCORE_Series : Single_TSeries_Indicator -{ - public ZSCORE_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - - double _pvar = 0; - for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } - _pvar /= this._buffer.Count; - double _psdev = Math.Sqrt(_pvar); - double _zscore = (_psdev == 0) ? double.NaN : (TValue.v - _sma) / _psdev; - - base.Add((TValue.t, _zscore), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/ALMA_Series.cs b/Calculations/Trends/ALMA_Series.cs deleted file mode 100644 index 30d755f5..00000000 --- a/Calculations/Trends/ALMA_Series.cs +++ /dev/null @@ -1,63 +0,0 @@ -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/ - - Discrepancy with Pandas-TA (but passes the validation with Skender.GetAlma) - - */ - -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) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - if (this._buffer.Count <= _p) - { - 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; - } - } - - double _weightedSum = 0; - for (int i = 0; i < this._buffer.Count; i++) - { _weightedSum += _weight[i] * _buffer[i]; } - double _alma = _weightedSum / _norm; - - base.Add((TValue.t, _alma), update, _NaN); - } -} diff --git a/Calculations/Momentum/CCI_Series.cs b/Calculations/Trends/CCI_Series.cs similarity index 100% rename from Calculations/Momentum/CCI_Series.cs rename to Calculations/Trends/CCI_Series.cs diff --git a/Calculations/Trends/DEMA_Series.cs b/Calculations/Trends/DEMA_Series.cs deleted file mode 100644 index 6dea06e5..00000000 --- a/Calculations/Trends/DEMA_Series.cs +++ /dev/null @@ -1,72 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; -using System.Runtime.CompilerServices; - -/* -DEMA: Double 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/ - -Remark: - ema1 = EMA(close, length) - ema2 = EMA(ema1, length) - DEMA = 2 * ema1 - ema2 - - */ - -public class DEMA_Series : Single_TSeries_Indicator -{ - private readonly double _k; - private int _len; - private readonly bool _useSMA; - private double _sum, _lastsum, _lastlastsum; - private double _lastema1, _lastlastema1; - private double _lastema2, _lastlastema2; - - public DEMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) - { - _k = 2.0 / (_p + 1); - _len = 0; - _useSMA = useSMA; - _sum = _lastema1 = _lastema2 =0; - if (_data.Count > 0) { base.Add(_data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - if (update) { - _lastsum = _lastlastsum; - _lastema1 = _lastlastema1; - _lastema2 = _lastlastema2; - } - else { - _lastlastsum = _lastsum; - _lastlastema1 = _lastema1; - _lastlastema2 = _lastema2; - _len++; - } - - double _ema1, _ema2, _dema; - if (this.Count == 0) { - _ema1 = _ema2 = _sum = TValue.v; - } - else if (_len <= _period && _useSMA && _period != 0) { - _sum += TValue.v; - _ema1 = _sum / Math.Min(_len, _period); - _ema2 = _ema1; - } - else { - _ema1 = (TValue.v - _lastema1) * _k + _lastema1; - _ema2 = (_ema1 - _lastema2) * _k + _lastema2; - } - _dema = 2*_ema1 - _ema2; - - _lastema1 = Double.IsNaN(_ema1)?_lastema1:_ema1; - _lastema2 = Double.IsNaN(_ema2)?_lastema2:_ema2; - - base.Add((TValue.t, _dema), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/DWMA_Series.cs b/Calculations/Trends/DWMA_Series.cs deleted file mode 100644 index 08d2ecb9..00000000 --- a/Calculations/Trends/DWMA_Series.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -DWMA: Double Weighted Moving Average - The weights are decreasing over the period with p^2 decay - and the most recent data has the heaviest weight. - - */ - -public class DWMA_Series : Single_TSeries_Indicator { - private readonly System.Collections.Generic.List _buffer1 = new(); - private readonly System.Collections.Generic.List _weights = new(); - public DWMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) { - for (int i = 0; i < this._p; i++) { - double _weight = (i + 1) * (i + 1); - this._weights.Add(_weight); - } - if (base._data.Count > 0) { base.Add(base._data); } - } - - public override void Add((System.DateTime t, double v) TValue, bool update) { - Add_Replace_Trim(_buffer1, TValue.v, _p, update); - double _wma1 = 0, _wsum = 0; - for (int i = 0; i < _buffer1.Count; i++) { - _wma1 += _buffer1[i] * _weights[i]; - _wsum += _weights[i]; - } - _wma1 /= _wsum; - - base.Add((TValue.t, _wma1), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/EMA_Series.cs b/Calculations/Trends/EMA_Series.cs deleted file mode 100644 index 6ce1d3a1..00000000 --- a/Calculations/Trends/EMA_Series.cs +++ /dev/null @@ -1,71 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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) - -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. - - */ - -public class EMA_Series : Single_TSeries_Indicator { - private double _k; - private double _lastema, _lastlastema; - private double _sum, _oldsum; - private int _len; - private readonly bool _useSMA; - - public EMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) { - _k = 2.0 / (_p + 1); - _sum = _oldsum = _lastema = _lastlastema = 0; - _len = 0; - _useSMA = useSMA; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - - if (update) { _lastema = _lastlastema; _sum = _oldsum; } - else { _lastlastema = _lastema; _oldsum = _sum; _len++; } - - double _ema = 0; - // when period = 0, create cumulative/additive series where _k is progressively larger - if (_period == 0) { _k = 2.0 / (_len + 1); } - - // the first value of the series - if (this.Count == 0) { - _ema = _sum = TValue.v; - } - // if SMA is used for seeding, calculate SMA within period - else if (_len <= _period && _useSMA && _period != 0) { - _sum += TValue.v; - if (_period != 0 && _len > _period) { - _sum -= (_data[base.Count - _period - (update ? 1 : 0)].v); - } - _ema = _sum / Math.Min(_len, _period); - } - // calculate EMA out from last EMA and factor k - else { - _ema = _k * (TValue.v - _lastema) + _lastema; - } - _lastema = Double.IsNaN(_ema)?_lastema:_ema; - - base.Add((TValue.t, _ema), update, _NaN); - } - public void Reset() { - _sum = _oldsum = _lastema = _lastlastema = 0; - _len = 0; - } -} \ No newline at end of file diff --git a/Calculations/Trends/FMA_Series.cs b/Calculations/Trends/FMA_Series.cs deleted file mode 100644 index c43a6679..00000000 --- a/Calculations/Trends/FMA_Series.cs +++ /dev/null @@ -1,59 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -FMA: Fibonacci Moving Average - FMA calculates the average across multiple EMAs with periods following Fibonacci sequence - (skipping initial Fibonacci numbers of 1, 1, 2) 3, 5, 8, 13, 21, 34... - - FMA(n) = Average(EMA(3), EMA(5), EMA(8), ema(13), ... EMA(n-th Fib)) - -Sources: - https://kaabar-sofien.medium.com/the-fibonacci-moving-average-the-full-guide-60e718117595 - https://usethinkscript.com/threads/fibonacci-moving-average.8099/ - - */ - -public class FMA_Series : Single_TSeries_Indicator { - readonly double[,] fib; - double _oldsum; - readonly int _len; - - public FMA_Series(TSeries source, int period) : base(source, period, false) { - _len = period; - fib = new double[_len, 4]; - int a = 3; - int b = 5; - int f = 0; - fib[0, 0] = 2 / ((double)a - 1); - if (_len > 1) { fib[1, 0] = 2 / ((double)b - 1); } - if (_len > 2) { - for (int i = 2; i < _len; i++) { - f = a + b; - a = b; - b = f; - fib[i, 0] = 2 / ((double)f - 1); - } - } - _oldsum = 0; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - double _sum = 0; - for (int i = 0; i < _len; i++) { - if (update) { fib[i, 1] = fib[i, 3]; _sum = _oldsum; } - else { fib[i, 3] = fib[i, 1]; _oldsum = _sum; } - - if (this.Count == 0) { fib[i, 1] = TValue.v; } - else { - fib[i, 2] = fib[i, 0] * (TValue.v - fib[i, 1]) + fib[i, 1]; - fib[i, 1] = fib[i, 2]; - } - _sum += fib[i, 1]; - } - - double _fma = _sum / _len; - base.Add((TValue.t, _fma), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/HEMA_Series.cs b/Calculations/Trends/HEMA_Series.cs deleted file mode 100644 index dcb9d560..00000000 --- a/Calculations/Trends/HEMA_Series.cs +++ /dev/null @@ -1,57 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -HEMA: Hull-EMA Moving Average - a hybrid indicator - Modified HUll Moving Average; instead of using WMA (Weighted MA) for calculation, - 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 -{ - public HEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - this._k1 = 4 / ((period * 0.5) + 1); - this._k2 = 3 / (double)(period + 1); - this._k3 = 2 / (Math.Sqrt(period) + 1); - this._lastema1 = this._lastlastema1 = double.NaN; - this._lastema2 = this._lastlastema2 = double.NaN; - this._lastema3 = this._lastlastema3 = double.NaN; - - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly double _k1, _k2, _k3; - private double _lastema1, _lastlastema1; - private double _lastema2, _lastlastema2; - private double _lastema3, _lastlastema3; - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - if (update) - { - this._lastema1 = this._lastlastema1; - this._lastema2 = this._lastlastema2; - this._lastema3 = this._lastlastema3; - } - double _ema1 = System.Double.IsNaN(this._lastema1) ? TValue.v : TValue.v * this._k1 + this._lastema1 * (1 - this._k1); - double _ema2 = System.Double.IsNaN(this._lastema2) ? TValue.v : TValue.v * this._k2 + this._lastema2 * (1 - this._k2); - - double _rawhema = (2 * _ema1) - _ema2; - double _ema3 = System.Double.IsNaN(this._lastema3) ? _rawhema : _rawhema * this._k3 + this._lastema3 * (1 - this._k3); - - this._lastlastema1 = this._lastema1; - this._lastlastema2 = this._lastema2; - this._lastlastema3 = this._lastema3; - this._lastema1 = _ema1; - this._lastema2 = _ema2; - this._lastema3 = _ema3; - - base.Add((TValue.t, _ema3), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/HMA_Series.cs b/Calculations/Trends/HMA_Series.cs deleted file mode 100644 index 8a522fba..00000000 --- a/Calculations/Trends/HMA_Series.cs +++ /dev/null @@ -1,119 +0,0 @@ -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. - -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 -{ - private readonly int _p; - private readonly bool _NaN; - private readonly TSeries _data; - private double _wma1, _wma2; - private readonly System.Collections.Generic.List _buf1 = new(); - private readonly System.Collections.Generic.List _buf2 = new(); - private readonly System.Collections.Generic.List _buf3 = new(); - private readonly System.Collections.Generic.List _weights = new(); - - public HMA_Series(TSeries source, int period, bool useNaN = false) - { - this._p = period; - this._data = source; - this._NaN = useNaN; - for (int i = 0; i < this._p; i++) - { - this._weights.Add(i + 1); - } - - source.Pub += this.Sub; - if (source.Count > 0) - { - for (int i = 0; i < source.Count; i++) - { - this.Add(source[i], false); - } - } - } - public new void Add((System.DateTime t, double v) data, bool update = false) - { - if (update) - { - this._buf1[this._buf1.Count - 1] = data.v; - this._buf2[this._buf2.Count - 1] = data.v; - } - else - { - this._buf1.Add(data.v); - this._buf2.Add(data.v); - } - if (this._buf1.Count > (int)((double)this._p / 2)) - { - this._buf1.RemoveAt(0); - } - if (this._buf2.Count > this._p) - { - this._buf2.RemoveAt(0); - } - - this._wma1 = 0; - for (int i = 0; i < this._buf1.Count; i++) - { - this._wma1 += this._buf1[i] * this._weights[i]; - } - this._wma1 /= (this._buf1.Count * (this._buf1.Count + 1)) * 0.5; - - this._wma2 = 0; - for (int i = 0; i < this._buf2.Count; i++) - { - this._wma2 += this._buf2[i] * this._weights[i]; - } - this._wma2 /= (this._buf2.Count * (this._buf2.Count + 1)) * 0.5; - - if (update) - { - this._buf3[this._buf3.Count - 1] = 2 * this._wma1 - this._wma2; - } - else - { - this._buf3.Add(2 * this._wma1 - this._wma2); - } - - if (this._buf3.Count > (int)Math.Sqrt(this._p)) - { - this._buf3.RemoveAt(0); - } - - double _hma = 0; - for (int i = 0; i < this._buf3.Count; i++) - { - _hma += this._buf3[i] * this._weights[i]; - } - - _hma /= (this._buf3.Count * (this._buf3.Count + 1)) * 0.5; - - (System.DateTime t, double v) result = - (data.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _hma); - base.Add(result, update); - } - public void Add(bool update = false) - { - this.Add(this._data[this._data.Count - 1], update); - } - public new void Sub(object source, TSeriesEventArgs e) - { - this.Add(this._data[this._data.Count - 1], e.update); - } -} diff --git a/Calculations/Trends/KAMA_Series.cs b/Calculations/Trends/KAMA_Series.cs deleted file mode 100644 index 808ce8c7..00000000 --- a/Calculations/Trends/KAMA_Series.cs +++ /dev/null @@ -1,64 +0,0 @@ -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; - _lastkama = _lastlastkama; - } - else { - _buffer.Add(TValue.v); - _lastlastkama = _lastkama; - } - if (_buffer.Count > _p + 1) { _buffer.RemoveAt(0); } - - double _kama = 0; - if (this.Count < this._p) { _kama = TValue.v; } - 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))); - } - _lastkama = _kama; - base.Add((TValue.t, _kama), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/MAMA_Series.cs b/Calculations/Trends/MAMA_Series.cs index 624321a8..5a04d341 100644 --- a/Calculations/Trends/MAMA_Series.cs +++ b/Calculations/Trends/MAMA_Series.cs @@ -15,105 +15,144 @@ Sources: */ -public class MAMA_Series : Single_TSeries_Indicator -{ - public MAMA_Series(TSeries source, double fastlimit = 0.5, double slowlimit = 0.05, bool useNaN = false) : base(source, period: 5, useNaN) - { - fastl = fastlimit; - slowl = slowlimit; - Fama = new(); - if (base._data.Count > 0) { base.Add(base._data); } - } - private double sumPr, jI, jQ; - readonly double fastl, slowl; - private (double i, double i1, double i2, double i3, double i4, double i5, double i6, double io) pr, i1, q1, sm, dt; - private (double i, double i1, double io) i2, q2, re, im, pd, ph, mama, fama; - public TSeries Fama { get; } - public override void Add((System.DateTime t, double v) TValue, bool update) - { +public class MAMA_Series : Single_TSeries_Indicator { + public MAMA_Series(TSeries source, double fastlimit = 0.5, double slowlimit = 0.05, bool useNaN = false) : base(source, 5, useNaN) { + fastl = fastlimit; + slowl = slowlimit; + Fama = new TSeries(); + if (_data.Count > 0) { + base.Add(_data); + } + } - if (!update) { - // roll forward (oldx = x) - pr.io = pr.i6; pr.i6 = pr.i5; pr.i5 = pr.i4; pr.i4 = pr.i3; pr.i3 = pr.i2; pr.i2 = pr.i1; pr.i1 = pr.i; - i1.io = i1.i6; i1.i6 = i1.i5; i1.i5 = i1.i4; i1.i4 = i1.i3; i1.i3 = i1.i2; i1.i2 = i1.i1; i1.i1 = i1.i; - q1.io = q1.i6; q1.i6 = q1.i5; q1.i5 = q1.i4; q1.i4 = q1.i3; q1.i3 = q1.i2; q1.i2 = q1.i1; q1.i1 = q1.i; - dt.io = dt.i6; dt.i6 = dt.i5; dt.i5 = dt.i4; dt.i4 = dt.i3; dt.i3 = dt.i2; dt.i2 = dt.i1; dt.i1 = dt.i; - sm.io = sm.i6; sm.i6 = sm.i5; sm.i5 = sm.i4; sm.i4 = sm.i3; sm.i3 = sm.i2; sm.i2 = sm.i1; sm.i1 = sm.i; - i2.io = i2.i1; i2.i1 = i2.i; - q2.io = q2.i1; q2.i1 = q2.i; - re.io = re.i1; re.i1 = re.i; - im.io = im.i1; im.i1 = im.i; - pd.io = pd.i1; pd.i1 = pd.i; - ph.io = ph.i1; ph.i1 = ph.i; - mama.io = mama.i1; mama.i1 = mama.i; - fama.io = fama.i1; fama.i1 = fama.i; - } - int i = base.Count; - pr.i = TValue.v; - if (i > 5) { - double adj = (0.075 * pd.i1) + 0.54; + private double sumPr, jI, jQ; + private readonly double fastl, slowl; + private (double i, double i1, double i2, double i3, double i4, double i5, double i6, double io) pr, i1, q1, sm, dt; + private (double i, double i1, double io) i2, q2, re, im, pd, ph, mama, fama; + public TSeries Fama { get; } - // smooth and detrender - sm.i = ((4 * pr.i) + (3 * pr.i1) + (2 * pr.i2) + pr.i3) / 10; - dt.i = ((0.0962 * sm.i) + (0.5769 * sm.i2) - (0.5769 * sm.i4) - (0.0962 * sm.i6)) * adj; + public override void Add((DateTime t, double v) TValue, bool update) { + if (!update) { + // roll forward (oldx = x) + pr.io = pr.i6; + pr.i6 = pr.i5; + pr.i5 = pr.i4; + pr.i4 = pr.i3; + pr.i3 = pr.i2; + pr.i2 = pr.i1; + pr.i1 = pr.i; + i1.io = i1.i6; + i1.i6 = i1.i5; + i1.i5 = i1.i4; + i1.i4 = i1.i3; + i1.i3 = i1.i2; + i1.i2 = i1.i1; + i1.i1 = i1.i; + q1.io = q1.i6; + q1.i6 = q1.i5; + q1.i5 = q1.i4; + q1.i4 = q1.i3; + q1.i3 = q1.i2; + q1.i2 = q1.i1; + q1.i1 = q1.i; + dt.io = dt.i6; + dt.i6 = dt.i5; + dt.i5 = dt.i4; + dt.i4 = dt.i3; + dt.i3 = dt.i2; + dt.i2 = dt.i1; + dt.i1 = dt.i; + sm.io = sm.i6; + sm.i6 = sm.i5; + sm.i5 = sm.i4; + sm.i4 = sm.i3; + sm.i3 = sm.i2; + sm.i2 = sm.i1; + sm.i1 = sm.i; + i2.io = i2.i1; + i2.i1 = i2.i; + q2.io = q2.i1; + q2.i1 = q2.i; + re.io = re.i1; + re.i1 = re.i; + im.io = im.i1; + im.i1 = im.i; + pd.io = pd.i1; + pd.i1 = pd.i; + ph.io = ph.i1; + ph.i1 = ph.i; + mama.io = mama.i1; + mama.i1 = mama.i; + fama.io = fama.i1; + fama.i1 = fama.i; + } - // in-phase and quadrature - q1.i = ((0.0962 * dt.i) + (0.5769 * dt.i2) - (0.5769 * dt.i4) - (0.0962 * dt.i6)) * adj; - i1.i = dt.i3; + var i = Count; + pr.i = TValue.v; + if (i > 5) { + var adj = 0.075 * pd.i1 + 0.54; - // advance the phases by 90 degrees - jI = ((0.0962 * i1.i) + (0.5769 * i1.i2) - (0.5769 * i1.i4) - (0.0962 * i1.i6)) * adj; - jQ = ((0.0962 * q1.i) + (0.5769 * q1.i2) - (0.5769 * q1.i4) - (0.0962 * q1.i6)) * adj; + // smooth and detrender + sm.i = (4 * pr.i + 3 * pr.i1 + 2 * pr.i2 + pr.i3) / 10; + dt.i = (0.0962 * sm.i + 0.5769 * sm.i2 - 0.5769 * sm.i4 - 0.0962 * sm.i6) * adj; - // phasor addition for 3-bar averaging - i2.i = i1.i - jQ; - q2.i = q1.i + jI; + // in-phase and quadrature + q1.i = (0.0962 * dt.i + 0.5769 * dt.i2 - 0.5769 * dt.i4 - 0.0962 * dt.i6) * adj; + i1.i = dt.i3; - i2.i = (0.2 * i2.i) + (0.8 * i2.i1); // smoothing it - q2.i = (0.2 * q2.i) + (0.8 * q2.i1); + // advance the phases by 90 degrees + jI = (0.0962 * i1.i + 0.5769 * i1.i2 - 0.5769 * i1.i4 - 0.0962 * i1.i6) * adj; + jQ = (0.0962 * q1.i + 0.5769 * q1.i2 - 0.5769 * q1.i4 - 0.0962 * q1.i6) * adj; - // homodyne discriminator - re.i = (i2.i * i2.i1) + (q2.i * q2.i1); - im.i = (i2.i * q2.i1) - (q2.i * i2.i1); + // phasor addition for 3-bar averaging + i2.i = i1.i - jQ; + q2.i = q1.i + jI; - re.i = (0.2 * re.i) + (0.8 * re.i1); // smoothing it - im.i = (0.2 * im.i) + (0.8 * im.i1); + i2.i = 0.2 * i2.i + 0.8 * i2.i1; // smoothing it + q2.i = 0.2 * q2.i + 0.8 * q2.i1; - // calculate period - pd.i = (im.i != 0 && re.i != 0) ? (6.283185307179586 / Math.Atan(im.i / re.i)) : 0d; + // homodyne discriminator + re.i = i2.i * i2.i1 + q2.i * q2.i1; + im.i = i2.i * q2.i1 - q2.i * i2.i1; - // adjust period to thresholds - pd.i = (pd.i > 1.5 * pd.i1) ? 1.5 * pd.i1 : pd.i; - pd.i = (pd.i < 0.67 * pd.i1) ? 0.67 * pd.i1 : pd.i; - pd.i = (pd.i < 6d) ? 6d : pd.i; - pd.i = (pd.i > 50d) ? 50d : pd.i; + re.i = 0.2 * re.i + 0.8 * re.i1; // smoothing it + im.i = 0.2 * im.i + 0.8 * im.i1; - // smooth the period - pd.i = (0.2 * pd.i) + (0.8 * pd.i1); + // calculate period + pd.i = im.i != 0 && re.i != 0 ? 6.283185307179586 / Math.Atan(im.i / re.i) : 0d; - // determine phase position - ph.i = (i1.i != 0) ? Math.Atan(q1.i / i1.i) * 57.29577951308232 : 0; + // adjust period to thresholds + pd.i = pd.i > 1.5 * pd.i1 ? 1.5 * pd.i1 : pd.i; + pd.i = pd.i < 0.67 * pd.i1 ? 0.67 * pd.i1 : pd.i; + pd.i = pd.i < 6d ? 6d : pd.i; + pd.i = pd.i > 50d ? 50d : pd.i; - // change in phase - double delta = Math.Max(ph.i1 - ph.i, 1d); + // smooth the period + pd.i = 0.2 * pd.i + 0.8 * pd.i1; - // adaptive alpha value - double alpha = Math.Max(fastl / delta, slowl); + // determine phase position + ph.i = i1.i != 0 ? Math.Atan(q1.i / i1.i) * 57.29577951308232 : 0; - // final indicators - mama.i = ((alpha * pr.i) + ((1d - alpha) * mama.i1)); - fama.i = ((0.5d * alpha * mama.i) + ((1d - (0.5d * alpha)) * fama.i1)); - } - else { - sumPr += pr.i; - pd.i = sm.i = dt.i = i1.i = q1.i = i2.i = q2.i = re.i = im.i = ph.i = 0; - mama.i = fama.i = sumPr / (i+1); - } + // change in phase + var delta = Math.Max(ph.i1 - ph.i, 1d); - base.Add((TValue.t, mama.i), update, _NaN); - var result = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : fama.i); - Fama.Add(result, update); - } + // adaptive alpha value + var alpha = Math.Max(fastl / delta, slowl); + + // final indicators + mama.i = alpha * pr.i + (1d - alpha) * mama.i1; + fama.i = 0.5d * alpha * mama.i + (1d - 0.5d * alpha) * fama.i1; + } + else { + sumPr += pr.i; + pd.i = sm.i = dt.i = i1.i = q1.i = i2.i = q2.i = re.i = im.i = ph.i = 0; + mama.i = fama.i = sumPr / (i + 1); + } + + base.Add((TValue.t, mama.i), update, _NaN); + var result = (TValue.t, Count < _p - 1 && _NaN ? double.NaN : fama.i); + Fama.Add(result, update); + } } diff --git a/Calculations/Trends/RMA_Series.cs b/Calculations/Trends/RMA_Series.cs deleted file mode 100644 index f7059c51..00000000 --- a/Calculations/Trends/RMA_Series.cs +++ /dev/null @@ -1,56 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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. - -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 - -Issues: - Pandas-TA library calculates RMA using straight Exponential Weighted Mean: - pandas.ewm().mean() and returns incorrect first (period) of bars compared to - published formula. This implementation passess the validation test in Wilder's book. - - */ - -public class RMA_Series : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer = new(); - private readonly double _k, _k1m; - private double _lastema, _lastlastema; - - public RMA_Series(TSeries 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 (_data.Count > 0) { base.Add(_data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - double _ema; - if (update) { this._lastema = this._lastlastema; } - - if (this.Count < this._p) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - _ema = _buffer.Average(); - } - else - { - _ema = (TValue.v * _k) + (_lastema * _k1m); - } - - this._lastlastema = this._lastema; - this._lastema = _ema; - - base.Add((TValue.t, _ema), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/SMA_Series.cs b/Calculations/Trends/SMA_Series.cs deleted file mode 100644 index 84c8395d..00000000 --- a/Calculations/Trends/SMA_Series.cs +++ /dev/null @@ -1,44 +0,0 @@ -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 - -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 (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 { - private double _sum, _oldsum; - private int _len; - - public SMA_Series(TSeries source, int period = 0, bool useNaN = false) : base(source, period, false) { - _sum = _oldsum = 0; - _len = 0; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - if (update) { _sum = _oldsum; } - else { _oldsum = _sum; _len++; } - - _sum += TValue.v; - if (_period != 0 && _len > _period) { - _sum -= (_data[base.Count - _period - (update ? 1 : 0)].v); - } - double _div = (_period == 0) ? _len : Math.Min(_len, _period); - base.Add((TValue.t, _sum / _div), update, _NaN); - } - public void Reset() { - _sum = _oldsum = 0; - _len = 0; - } -} diff --git a/Calculations/Trends/SMMA_Series.cs b/Calculations/Trends/SMMA_Series.cs deleted file mode 100644 index 27d3bfcd..00000000 --- a/Calculations/Trends/SMMA_Series.cs +++ /dev/null @@ -1,51 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -SMMA: Smoothed Moving Average - The Smoothed Moving Average (SMMA) is a combination of a SMA and an EMA. It gives the recent prices - an equal weighting as the historic prices as it takes all available price data into account. - The main advantage of a smoothed moving average is that it removes short-term fluctuations. - - SMMA(i) = (SMMA-1*(N-1) + CLOSE (i)) / N - -Sources: - https://blog.earn2trade.com/smoothed-moving-average - https://guide.traderevolution.com/traderevolution/mobile-applications/phone/android/technical-indicators/moving-averages/smma-smoothed-moving-average - https://www.chartmill.com/documentation/technical-analysis-indicators/217-MOVING-AVERAGES-%7C-The-Smoothed-Moving-Average-%28SMMA%29 - - */ - -public class SMMA_Series : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer = new(); - private double _lastsmma, _lastlastsmma; - - public SMMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - this._lastsmma = this._lastlastsmma = double.NaN; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - double _smma = 0; - if (update) { this._lastsmma = this._lastlastsmma; } - - if (this.Count < this._p) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - _smma = _buffer.Average(); - } - else - { - _smma = ((_lastsmma * (_p-1)) + TValue.v) / _p ; - } - - this._lastlastsmma = this._lastsmma; - this._lastsmma = _smma; - - base.Add((TValue.t, _smma), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/T3_Series.cs b/Calculations/Trends/T3_Series.cs deleted file mode 100644 index 4f598993..00000000 --- a/Calculations/Trends/T3_Series.cs +++ /dev/null @@ -1,100 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; -using System.Numerics; - -/* -T3: Tillson T3 Moving Average - Tim Tillson described it in "Technical Analysis of Stocks and Commodities", January 1998 in the - article "Better Moving Averages". Tillson’s moving average becomes a popular indicator of - technical analysis as it gets less lag with the price chart and its curve is considerably smoother. - -Sources: - https://technicalindicators.net/indicators-technical-analysis/150-t3-moving-average - http://www.binarytribune.com/forex-trading-indicators/t3-moving-average-indicator/ - - */ -public class T3_Series : Single_TSeries_Indicator { - private readonly double _k, _k1m, _c1, _c2, _c3, _c4; - private readonly System.Collections.Generic.List _buffer1 = new(); - private readonly System.Collections.Generic.List _buffer2 = new(); - private readonly System.Collections.Generic.List _buffer3 = new(); - private readonly System.Collections.Generic.List _buffer4 = new(); - private readonly System.Collections.Generic.List _buffer5 = new(); - private readonly System.Collections.Generic.List _buffer6 = new(); - - private double _lastema1, _lastema2, _lastema3, _lastema4, _lastema5, _lastema6; - private double _llastema1, _llastema2, _llastema3, _llastema4, _llastema5, _llastema6; - private readonly bool _useSMA; - - public T3_Series(TSeries source, int period, double vfactor = 0.7, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) { - double _a = vfactor; //0.7; //0.618 - _c1 = -_a * _a * _a; - _c2 = 3 * _a * _a + 3 * _a * _a * _a; - _c3 = -6 * _a * _a - 3 * _a - 3 * _a * _a * _a; - _c4 = 1 + 3 * _a + _a * _a * _a + 3 * _a * _a; - - _k = 2.0 / (_p + 1); - _k1m = 1.0 - _k; - _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = _lastema4 = _llastema4 = _lastema5 = _llastema5 = _lastema5 = _llastema5 = 0; - _useSMA = useSMA; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - double _ema1, _ema2, _ema3, _ema4, _ema5, _ema6; - if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; _lastema4 = _llastema4; _lastema5 = _llastema5; _lastema6 = _llastema6; } - else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; _llastema4 = _lastema4; _llastema5 = _lastema5; _llastema6 = _lastema6; } - - if (this.Count == 0) { _lastema1 = _lastema2 = _lastema3 = _lastema4 = _lastema5 = _lastema6 = TValue.v; } - - if ((this.Count < _p) && _useSMA) { - Add_Replace(_buffer1, TValue.v, update); - _ema1 = 0; - for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; } - _ema1 /= _buffer1.Count; - - Add_Replace(_buffer2, _ema1, update); - _ema2 = 0; - for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; } - _ema2 /= _buffer2.Count; - - Add_Replace(_buffer3, _ema2, update); - _ema3 = 0; - for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; } - _ema3 /= _buffer3.Count; - - Add_Replace(_buffer4, _ema3, update); - _ema4 = 0; - for (int i = 0; i < _buffer4.Count; i++) { _ema4 += _buffer4[i]; } - _ema4 /= _buffer4.Count; - - Add_Replace(_buffer5, _ema4, update); - _ema5 = 0; - for (int i = 0; i < _buffer5.Count; i++) { _ema5 += _buffer5[i]; } - _ema5 /= _buffer5.Count; - - Add_Replace(_buffer6, _ema5, update); - _ema6 = 0; - for (int i = 0; i < _buffer6.Count; i++) { _ema6 += _buffer6[i]; } - _ema6 /= _buffer6.Count; - } - 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); - _ema4 = (_ema3 * this._k) + (this._lastema4 * this._k1m); - _ema5 = (_ema4 * this._k) + (this._lastema5 * this._k1m); - _ema6 = (_ema5 * this._k) + (this._lastema6 * this._k1m); - } - _lastema1 = _ema1; - _lastema2 = _ema2; - _lastema3 = _ema3; - _lastema4 = _ema4; - _lastema5 = _ema5; - _lastema6 = _ema6; - - double _T3 = _c1 * _ema6 + _c2 * _ema5 + _c3 * _ema4 + _c4 * _ema3; - base.Add((TValue.t, _T3), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/TEMA_Series.cs b/Calculations/Trends/TEMA_Series.cs deleted file mode 100644 index 71f84698..00000000 --- a/Calculations/Trends/TEMA_Series.cs +++ /dev/null @@ -1,70 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -TEMA: Triple 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/ - -Remark: - ema1 = EMA(close, length) - ema2 = EMA(ema1, length) - ema3 = EMA(ema2, length) - TEMA = 3 * (ema1 - ema2) + ema3 - - */ - -public class TEMA_Series : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _buffer = new(); - private readonly double _k, _k1m; - private double _lastema1, _lastlastema1; - private double _lastema2, _lastlastema2; - private double _lastema3, _lastlastema3; - - public TEMA_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; - if (_data.Count > 0) { base.Add(_data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - if (update) - { - this._lastema1 = this._lastlastema1; - this._lastema2 = this._lastlastema2; - this._lastema3 = this._lastlastema3; - } - - double _ema1, _ema2, _ema3; - - if (this.Count < this._p) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - double _sma = _buffer.Average(); - _ema1 = _ema2 = _ema3 = _sma; - } - 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); - } - - double _tema = (3 * (_ema1 - _ema2)) + _ema3; - - this._lastlastema1 = this._lastema1; - this._lastlastema2 = this._lastema2; - this._lastlastema3 = this._lastema3; - this._lastema1 = _ema1; - this._lastema2 = _ema2; - this._lastema3 = _ema3; - - base.Add((TValue.t, _tema), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/TRIMA_Series.cs b/Calculations/Trends/TRIMA_Series.cs deleted file mode 100644 index 7a082b7e..00000000 --- a/Calculations/Trends/TRIMA_Series.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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 = _buffer1.Average(); - - if (update) { _buffer2[_buffer2.Count - 1] = _sma1; } else { _buffer2.Add(_sma1); } - if (_buffer2.Count > this._p1a && this._p1a != 0) { _buffer2.RemoveAt(0); } - double _trima = _buffer2.Average(); - - base.Add((TValue.t, _trima), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/TRIX_Series.cs b/Calculations/Trends/TRIX_Series.cs deleted file mode 100644 index 7815048c..00000000 --- a/Calculations/Trends/TRIX_Series.cs +++ /dev/null @@ -1,75 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; -using System.Numerics; - -/* -TRIX: Triple Exponential Average - Developed by Jack Hutson in the early 1980s, the triple exponential average (TRIX) - has become a popular technical analysis tool to aid chartists in spotting diversions -and directional cues in stock trading patterns. - -Sources: - https://www.investopedia.com/terms/t/trix.asp - - */ -public class TRIX_Series : Single_TSeries_Indicator -{ - private readonly double _k, _k1m; - private readonly System.Collections.Generic.List _buffer1 = new(); - private readonly System.Collections.Generic.List _buffer2 = new(); - private readonly System.Collections.Generic.List _buffer3 = new(); - - private double _lastema1, _lastema2, _lastema3; - private double _llastema1, _llastema2, _llastema3; - private readonly bool _useSMA; - - public TRIX_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) - { - - _k = 2.0 / (_p + 1); - _k1m = 1.0 - _k; - _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = 0; - _useSMA = useSMA; - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) - { - double _ema1, _ema2, _ema3; - if (this.Count == 0) { _lastema1 = _lastema2 = _lastema3 = TValue.v; } - - if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; } - else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; } - - if ((this.Count < _p) && _useSMA) - { - Add_Replace(_buffer1, TValue.v, update); - _ema1 = 0; - for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; } - _ema1 /= _buffer1.Count; - - Add_Replace(_buffer2, _ema1, update); - _ema2 = 0; - for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; } - _ema2 /= _buffer2.Count; - - Add_Replace(_buffer3, _ema2, update); - _ema3 = 0; - for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; } - _ema3 /= _buffer3.Count; - } - 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); - } - double _trix = 100 * (_ema3 - _lastema3) / _lastema3; - _lastema1 = _ema1; - _lastema2 = _ema2; - _lastema3 = _ema3; - - base.Add((TValue.t, _trix), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/WMA_Series.cs b/Calculations/Trends/WMA_Series.cs deleted file mode 100644 index 2b835b7f..00000000 --- a/Calculations/Trends/WMA_Series.cs +++ /dev/null @@ -1,35 +0,0 @@ -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. - -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 -{ - public WMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) - { - for (int i = 0; i < this._p; i++) { this._weights.Add(i + 1); } - if (base._data.Count > 0) { base.Add(base._data); } - } - private readonly System.Collections.Generic.List _buffer = new(); - private readonly System.Collections.Generic.List _weights = new(); - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - Add_Replace_Trim(_buffer, TValue.v, _p, update); - - double _wma = 0; - for (int i = 0; i < _buffer.Count; i++) { _wma += _buffer[i] * this._weights[i]; } - _wma /= (this._buffer.Count * (this._buffer.Count + 1)) * 0.5; - - base.Add((TValue.t, _wma), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Trends/ZLEMA_Series.cs b/Calculations/Trends/ZLEMA_Series.cs deleted file mode 100644 index a72da3ce..00000000 --- a/Calculations/Trends/ZLEMA_Series.cs +++ /dev/null @@ -1,62 +0,0 @@ -namespace QuanTAlib; -using System; -using System.Linq; - -/* -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, _lastema_o; - private int _llag; - private readonly bool _useSMA; - - public ZLEMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN) - { - this._k = 2.0 / (this._p + 1); - this._k1m = 1.0 - this._k; - this._lastema = this._lastema_o = double.NaN; - _llag = (int)((_p-1) * 0.5); - _useSMA = useSMA; - if (_data.Count > 0) { base.Add(_data); } - } - - public override void Add((System.DateTime t, double v) TValue, bool update) - { - int _lag = Math.Max(this.Count-_llag, 0); - if (update) { - _lastema = _lastema_o; _lag--; - } else { - _lastema_o = _lastema; - } - double _zl = TValue.v + (TValue.v - _data[_lag].v); - double _ema = 0; - - if (this.Count < this._p && _useSMA) { - Add_Replace_Trim(_buffer, _zl, _p, update); - _ema = _buffer.Average(); - } else { - _ema = (_zl * _k) + (_lastema * _k1m); - } - _lastema = _ema; - - base.Add((TValue.t, _ema), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Volatility/ATRP_Series.cs b/Calculations/Volatility/ATRP_Series.cs index 086db3db..3f4457ea 100644 --- a/Calculations/Volatility/ATRP_Series.cs +++ b/Calculations/Volatility/ATRP_Series.cs @@ -19,7 +19,7 @@ public class ATRP_Series : Single_TBars_Indicator { public ATRP_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) { _period = period; - _k = 1.0 / (double)(_p); + _k = 1.0 / (double)(_period); _lastatr = _lastlastatr = _cm1 = _lastcm1 = _sum = _oldsum = 0; if (this._bars.Count > 0) { base.Add(this._bars); } } diff --git a/Calculations/Volatility/CMO_Series.cs b/Calculations/Volatility/CMO_Series.cs deleted file mode 100644 index 6cabc235..00000000 --- a/Calculations/Volatility/CMO_Series.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -CMO: Chande Momentum Oscillator - Chande Momentum Oscillator (also known as CMO indicator) was developed by Tushar S. Chande - CMO is similar to other momentum oscillators (e.g. RSI or Stochastics). Alike RSI oscillator, - the CMO values move in the range from -100 to +100 points and its aim is to detect the - overbought and oversold market conditions. CMO calculates the price momentum on both the up - days as well as the down days. The CMO calculation is based on non-smoothed price values - meaning that it can reach its extremes more frequently and the short-time swings are more visible. - -Sources: - https://www.technicalindicators.net/indicators-technical-analysis/144-cmo-chande-momentum-oscillator - - */ - -public class CMO_Series : Single_TSeries_Indicator { - private readonly System.Collections.Generic.List _buff_up = new(); - private readonly System.Collections.Generic.List _buff_dn = new(); - private double _plast_value, _last_value; - - public CMO_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) { - if (this._data.Count > 0) { base.Add(this._data); } - } - - public override void Add((DateTime t, double v) TValue, bool update) { - if (this.Count == 0) { _plast_value = _last_value = TValue.v; } - if (update) {_last_value = _plast_value;} else {_plast_value = _last_value;} - - Add_Replace_Trim(_buff_up, (TValue.v > _last_value) ? TValue.v-_last_value : 0, _p, update); - Add_Replace_Trim(_buff_dn, (TValue.v < _last_value) ? _last_value-TValue.v : 0, _p, update); - _last_value = TValue.v; - - double _cmo_up = 0; - double _cmo_dn = 0; - for (int i = 0; i < Math.Min(_buff_up.Count, _buff_dn.Count); i++) { - _cmo_up += _buff_up[i]; - _cmo_dn += _buff_dn[i]; - } - - double _cmo = 100 * (_cmo_up - _cmo_dn) / (_cmo_up + _cmo_dn); - if (_cmo_up + _cmo_dn == 0) {_cmo = 0;} - base.Add((TValue.t, _cmo), update, _NaN); - } -} \ No newline at end of file diff --git a/Calculations/Volume/OBV_Series.cs b/Calculations/Volatility/OBV_Series.cs similarity index 100% rename from Calculations/Volume/OBV_Series.cs rename to Calculations/Volatility/OBV_Series.cs diff --git a/Calculations/Volatility/RSI_Series.cs b/Calculations/Volatility/RSI_Series.cs deleted file mode 100644 index 0805df35..00000000 --- a/Calculations/Volatility/RSI_Series.cs +++ /dev/null @@ -1,78 +0,0 @@ -namespace QuanTAlib; -using System; - -/* -RSI: Relative Strength Index - Created by J. Welles Wilder, the Relative Strength Index measures strength - of the winning/losing streak over N lookback periods on a scale of 0 to 100, - to depict overbought and oversold conditions. - -Sources: - https://www.investopedia.com/terms/r/rsi.asp - - */ - -public class RSI_Series : Single_TSeries_Indicator -{ - private readonly System.Collections.Generic.List _gain = new(); - private readonly System.Collections.Generic.List _loss = new(); - private double _avgGain, _avgLoss, _lastValue; - private double _avgGain_o, _avgLoss_o, _lastValue_o; - private int i; - - public RSI_Series(TSeries source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN) { - i = 0; - if (source.Count > 0) { base.Add(source); } - } - - public override void Add((System.DateTime t, double v) TValue, bool update) { - double _rsi = 0; - if (update) { - _lastValue = _lastValue_o; - _avgGain = _avgGain_o; - _avgLoss = _avgLoss_o; - } - else { - _lastValue_o = _lastValue; - _avgGain_o = _avgGain; - _avgLoss_o = _avgLoss; - } - - if (i == 0) { _lastValue = TValue.v; } - - double _gainval = (TValue.v > _lastValue) ? TValue.v - _lastValue : 0; - Add_Replace_Trim(_gain, _gainval, _p, update); - double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0; - Add_Replace_Trim(_loss, _lossval, _p, update); - _lastValue = TValue.v; - - // calculate RSI - if (i > _p) - { - _avgGain = ((_avgGain * (_p - 1)) + _gain[_gain.Count - 1]) / _p; - _avgLoss = ((_avgLoss * (_p - 1)) + _loss[_loss.Count - 1]) / _p; - if (_avgLoss > 0) { - double rs = _avgGain / _avgLoss; - _rsi = 100 - (100 / (1 + rs)); - } - else { _rsi = 100; } - } - // initialize average gain - else - { - double _sumGain = 0; - for (int p = 0; p < _gain.Count; p++) { _sumGain += _gain[p]; } - double _sumLoss = 0; - for (int p = 0; p < _loss.Count; p++) { _sumLoss += _loss[p]; } - - _avgGain = _sumGain / _gain.Count; - _avgLoss = _sumLoss / _loss.Count; - - _rsi = (_avgLoss > 0) ? 100 - (100 / (1 + (_avgGain / _avgLoss))) : 100; - } - - if (!update) { i++; } - var result = (TValue.t, (this.Count < this._p && this._NaN) ? double.NaN : _rsi); - base.Add(result, update); - } -} \ No newline at end of file diff --git a/Calculations/_Updated/ALMA_Series.cs b/Calculations/_Updated/ALMA_Series.cs new file mode 100644 index 00000000..18ba3339 --- /dev/null +++ b/Calculations/_Updated/ALMA_Series.cs @@ -0,0 +1,107 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Linq; + +/* +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/ + + Discrepancy with Pandas-TA (but passes the validation with Skender.GetAlma) + */ + +public class ALMA_Series : TSeries { + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + private readonly System.Collections.Generic.List _buffer = new(); + private readonly System.Collections.Generic.List _weight = new(); + private double _norm; + private readonly double _offset, _sigma; + + //core constructors + public ALMA_Series(int period, double offset, double sigma, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"ALMA({period})"; + _offset = offset; + _sigma = sigma; + _weight = new(); + } + public ALMA_Series(TSeries source, int period, double offset, double sigma, bool useNaN) : this(period, offset, sigma, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + + public ALMA_Series() : this(period:0, offset:0.85, sigma:6.0, useNaN: false) { } + public ALMA_Series(int period) : this(period: period, offset:0.85, sigma:6.0, useNaN:false) { } + public ALMA_Series(TBars source) : this(source:source.Close, period:0, offset:0.85, sigma:6.0, useNaN:false) { } + public ALMA_Series(TBars source, int period) : this(source:source.Close, period:period, offset: 0.85, sigma: 6.0, useNaN: false) { } + public ALMA_Series(TBars source, int period, double offset, double sigma, bool useNaN) : this(source.Close, period:period, offset: offset, sigma: sigma, useNaN: false) { } + public ALMA_Series(TSeries source) : this(source, period:0, offset:0.85, sigma:6.0, useNaN:false) { } + public ALMA_Series(TSeries source, int period) : this(source:source, period:period, offset:0.85, sigma:6.0, useNaN:false) { } + public ALMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, offset: 0.85, sigma: 6.0, useNaN: useNaN) { } + + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update=false) { + BufferTrim(_buffer, TValue.v, _period, update); + if (_weight.Count < _buffer.Count) { + for (int i = 0; i < (_buffer.Count - _weight.Count); i++) { _weight.Add(0.0); } + } + if (this._buffer.Count <= _period || _period ==0) { + 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; + } + } + + double _weightedSum = 0; + for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; } + double _alma = _weightedSum / _norm; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _alma); + return base.Add(res, update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + _weight.Clear(); + } + + //variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/BIAS_Series.cs b/Calculations/_Updated/BIAS_Series.cs new file mode 100644 index 00000000..8fa734d5 --- /dev/null +++ b/Calculations/_Updated/BIAS_Series.cs @@ -0,0 +1,75 @@ +namespace QuanTAlib; +using System; + +/* +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 + = (close / SMA) - 1 + +Sources: + https://en.wikipedia.org/wiki/Bias_of_an_estimator + + */ + +public class BIAS_Series : TSeries { + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private readonly SMA_Series _sma; + + //core constructors + public BIAS_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"BIAS({period})"; + _sma = new(period, false); + } + public BIAS_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public BIAS_Series() : this(period: 0, useNaN: false) { } + public BIAS_Series(int period) : this(period: period, useNaN: false) { } + public BIAS_Series(TBars source) : this(source.Close, 0, false) { } + public BIAS_Series(TBars source, int period) : this(source.Close, period, false) { } + public BIAS_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public BIAS_Series(TSeries source) : this(source, 0, false) { } + public BIAS_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + var _s = _sma.Add(TValue,update); + double _bias = (TValue.v / ((_s.v!=0)?_s.v:1)) - 1; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _bias); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _sma.Reset(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/CMO_Series.cs b/Calculations/_Updated/CMO_Series.cs new file mode 100644 index 00000000..6a7520b1 --- /dev/null +++ b/Calculations/_Updated/CMO_Series.cs @@ -0,0 +1,92 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +CMO: Chande Momentum Oscillator + Chande Momentum Oscillator (also known as CMO indicator) was developed by Tushar S. Chande + CMO is similar to other momentum oscillators (e.g. RSI or Stochastics). Alike RSI oscillator, + the CMO values move in the range from -100 to +100 points and its aim is to detect the + overbought and oversold market conditions. CMO calculates the price momentum on both the up + days as well as the down days. The CMO calculation is based on non-smoothed price values + meaning that it can reach its extremes more frequently and the short-time swings are more visible. + +Sources: + https://www.technicalindicators.net/indicators-technical-analysis/144-cmo-chande-momentum-oscillator + + */ + +public class CMO_Series : TSeries { + private readonly System.Collections.Generic.List _buff_up = new(); + private readonly System.Collections.Generic.List _buff_dn = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private double _plast_value, _last_value; + + //core constructors + public CMO_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"CMO({period})"; + } + public CMO_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public CMO_Series() : this(period: 0, useNaN: false) { } + public CMO_Series(int period) : this(period: period, useNaN: false) { } + public CMO_Series(TBars source) : this(source.Close, 0, false) { } + public CMO_Series(TBars source, int period) : this(source.Close, period, false) { } + public CMO_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public CMO_Series(TSeries source) : this(source, 0, false) { } + public CMO_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (update) { _last_value = _plast_value; } else { _plast_value = _last_value; } + BufferTrim(buffer:_buff_up, (TValue.v > _last_value) ? TValue.v - _last_value : 0, period:_period, update: update); + BufferTrim(buffer: _buff_dn, (TValue.v < _last_value) ? _last_value - TValue.v : 0, period: _period, update: update); + _last_value = TValue.v; + double _cmo_up = 0; + double _cmo_dn = 0; + for (int i = 0; i < Math.Min(_buff_up.Count, _buff_dn.Count); i++) { + _cmo_up += _buff_up[i]; + _cmo_dn += _buff_dn[i]; + } + double _cmo = 100 * (_cmo_up - _cmo_dn) / (_cmo_up + _cmo_dn); + if (_cmo_up + _cmo_dn == 0) { _cmo = 0; } + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _cmo); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buff_up.Clear(); + _buff_dn.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/CUSUM_Series.cs b/Calculations/_Updated/CUSUM_Series.cs new file mode 100644 index 00000000..333a1466 --- /dev/null +++ b/Calculations/_Updated/CUSUM_Series.cs @@ -0,0 +1,74 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +CUSUM: Cumulative Sum (aka Running Total) + SUM across a period provides a rolling sum of all values across the period. + If SUM values would be divided with period, the output would be SMA() + +Sources: + https://en.wikipedia.org/wiki/CUSUM + */ + +public class CUSUM_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public CUSUM_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"CUSUM({period})"; + } + public CUSUM_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public CUSUM_Series() : this(period: 0, useNaN: false) { } + public CUSUM_Series(int period) : this(period: period, useNaN: false) { } + public CUSUM_Series(TBars source) : this(source.Close, 0, false) { } + public CUSUM_Series(TBars source, int period) : this(source.Close, period, false) { } + public CUSUM_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public CUSUM_Series(TSeries source) : this(source, 0, false) { } + public CUSUM_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sum = 0; + for (int i = 0; i < _buffer.Count; i++) { _sum += _buffer[i]; } + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sum); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/DECAY_Series.cs b/Calculations/_Updated/DECAY_Series.cs new file mode 100644 index 00000000..194f639a --- /dev/null +++ b/Calculations/_Updated/DECAY_Series.cs @@ -0,0 +1,86 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +DECAY: + Linear decay can be modeled by a straight line with a negative slope of 1/period. + The value decreases in a straight line from the last maximum to 0. + Decay = Last Max - distance/period + + Exponential decay is modeled as an exponential curve with diminishing factor of + 1-1/p + + */ + +public class DECAY_Series : TSeries { + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private readonly bool _exp; + private double _pdecay, _ppdecay; + private readonly double _dfactor; + + //core constructors + public DECAY_Series(int period, bool exponential, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"DECAY({period})"; + _exp = exponential; + _dfactor = (_exp) ? 1.0 - 1.0 / (double)_period : 1 / (double)_period; + _pdecay = _ppdecay = 0; + } + public DECAY_Series(TSeries source, int period, bool exponential, bool useNaN) : this(period, exponential, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public DECAY_Series() : this(period: 0, exponential: false, useNaN: false) { } + public DECAY_Series(int period) : this(period: period, exponential: false, useNaN: false) { } + public DECAY_Series(TBars source) : this(source.Close, period: 0, exponential: false, useNaN: false) { } + public DECAY_Series(TBars source, int period) : this(source.Close, period: period, exponential:false, useNaN:false) { } + public DECAY_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, exponential: false, useNaN) { } + public DECAY_Series(TSeries source) : this(source, period: 0, exponential: false, useNaN:false) { } + public DECAY_Series(TSeries source, int period) : this(source: source, period: period, exponential: false, useNaN: false) { } + public DECAY_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, exponential: false, useNaN: useNaN) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN), update); + } + if (update) { _pdecay = _ppdecay; } + else { _ppdecay = _pdecay; } + + if (this.Count == 0) { _pdecay = TValue.v; } + double _decay = Math.Max(TValue.v, Math.Max((_exp) ? _pdecay * _dfactor : _pdecay - _dfactor, 0)); + _pdecay = _decay; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _decay); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _pdecay = _ppdecay = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/DEMA_Series.cs b/Calculations/_Updated/DEMA_Series.cs new file mode 100644 index 00000000..afec6a2c --- /dev/null +++ b/Calculations/_Updated/DEMA_Series.cs @@ -0,0 +1,131 @@ +namespace QuanTAlib; + +using System; +using System.Linq; + +/* +DEMA: Double 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/ + +Remark: + ema1 = EMA(close, length) + ema2 = EMA(ema1, length) + DEMA = 2 * ema1 - ema2 + + */ + +public class DEMA_Series : TSeries { + private double _k; + private double _sum, _oldsum; + private double _lastema1, _oldema1, _lastema2, _oldema2; + private int _len; + private readonly bool _useSMA; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + +//core constructor + public DEMA_Series(int period, bool useNaN, bool useSMA) : base() { + _period = period; + _NaN = useNaN; + _useSMA = useSMA; + Name = $"DEMA({period})"; + _k = 2.0 / (_period + 1); + _len = 0; + _sum = _oldsum = _lastema1 = _lastema2 = 0; + } + //generic constructors (source) + + public DEMA_Series() : this(0, false, true) {} + public DEMA_Series(int period) : this(period, false, true) {} + public DEMA_Series(TBars source) : this(source.Close, 0, false) {} + public DEMA_Series(TBars source, int period) : this(source.Close, period, false) {} + public DEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {} + public DEMA_Series(TSeries source, int period) : this(source, period, false, true) {} + public DEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {} + public DEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + +// core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (update) { + _lastema1 = _oldema1; + _lastema2 = _oldema2; + _sum = _oldsum; + } + else { + _oldema1 = _lastema1; + _oldema2 = _lastema2; + _oldsum = _sum; + _len++; + } + + if (_period == 0) { + _k = 2.0 / (_len + 1); + } + + double _ema1, _ema2, _dema; + if (Count == 0) { + _ema1 = _ema2 = _sum = TValue.v; + } + else if (_len <= _period && _useSMA && _period != 0) { + _sum += TValue.v; + _ema1 = _sum / Math.Min(_len, _period); + _ema2 = _ema1; + } + else { + _ema1 = (TValue.v - _lastema1) * _k + _lastema1; + _ema2 = (_ema1 - _lastema2) * _k + _lastema2; + } + + _dema = 2 * _ema1 - _ema2; + + _lastema1 = double.IsNaN(_ema1) ? _lastema1 : _ema1; + _lastema2 = double.IsNaN(_ema2) ? _lastema2 : _ema2; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _dema); + return base.Add(res, update); + } + +//variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { + return (DateTime.Today, double.NaN); + } + + foreach (var item in data) { + Add(item, false); + } + + return _data.Last; + } + + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + + public (DateTime t, double v) Add(bool update) { + return Add(_data.Last, update); + } + + public (DateTime t, double v) Add() { + return Add(_data.Last, false); + } + + private new void Sub(object source, TSeriesEventArgs e) { + Add(_data.Last, e.update); + } + + //reset calculation + public override void Reset() { + _sum = _oldsum = _lastema1 = _lastema2 = 0; + _len = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/DWMA_Series.cs b/Calculations/_Updated/DWMA_Series.cs new file mode 100644 index 00000000..91df946c --- /dev/null +++ b/Calculations/_Updated/DWMA_Series.cs @@ -0,0 +1,126 @@ +namespace QuanTAlib; + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +/* +DWMA: Double Weighted Moving Average + The weights are decreasing over the period with p^2 decay + and the most recent data has the heaviest weight. + + */ + +public class DWMA_Series : TSeries { + private readonly List _buffer = new(); + private List _weights = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + protected int _len; + +//core constructors + public DWMA_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"DWMA({period})"; + _len = 0; + _weights = CalculateWeights(_period); + } + + public DWMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + + public DWMA_Series() : this(0, false) { + } + + public DWMA_Series(int period) : this(period, false) { + } + + public DWMA_Series(TBars source) : this(source.Close, 0, false) { + } + + public DWMA_Series(TBars source, int period) : this(source.Close, period, false) { + } + + public DWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { + } + + public DWMA_Series(TSeries source, int period) : this(source, period, false) { + } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(_buffer, TValue.v, _period, update); + if (_period == 0) { + _len++; + _weights = CalculateWeights(_len); + } + + double _dwma = 0, _wsum = 0; + var bufferCount = _buffer.Count; + + var lockObj = new object(); + Parallel.For(0, bufferCount, i => + { + var temp = _buffer[i] * _weights[i]; + lock (lockObj) { + _dwma += temp; + _wsum += _weights[i]; + } + }); + _dwma /= _wsum; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _dwma); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { + return (DateTime.Today, double.NaN); + } + + foreach (var item in data) { + Add(item, false); + } + + return _data.Last; + } + + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + + public (DateTime t, double v) Add(bool update) { + return Add(_data.Last, update); + } + + public (DateTime t, double v) Add() { + return Add(_data.Last, false); + } + + private new void Sub(object source, TSeriesEventArgs e) { + Add(_data.Last, e.update); + } + + //calculating weights + private static List CalculateWeights(int period) { + var weights = new List(period); + for (var i = 0; i < period; i++) { + weights.Add((i + 1) * (i + 1)); + } + + return weights; + } + + //reset calculation + public override void Reset() { + _len = 0; + _buffer.Clear(); + _weights = CalculateWeights(_period); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/EMA_Series.cs b/Calculations/_Updated/EMA_Series.cs new file mode 100644 index 00000000..8136f7da --- /dev/null +++ b/Calculations/_Updated/EMA_Series.cs @@ -0,0 +1,123 @@ +namespace QuanTAlib; + +using System; +using System.Linq; + +/* +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) + +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. + + */ + +public class EMA_Series : TSeries { + private double _k; + private double _lastema, _oldema; + private double _sum, _oldsum; + private int _len; + private readonly bool _useSMA; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + +//core constructors + + public EMA_Series(int period, bool useNaN, bool useSMA) : base() { + _period = period; + _NaN = useNaN; + _useSMA = useSMA; + Name = $"EMA({period})"; + _k = 2.0 / (_period + 1); + _len = 0; + _sum = _oldsum = _lastema = _oldema = 0; + } + public EMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public EMA_Series() : this(0, false, true) {} + public EMA_Series(int period) : this(period, false, true) {} + public EMA_Series(TBars source) : this(source.Close, 0, false) {} + public EMA_Series(TBars source, int period) : this(source.Close, period, false) {} + public EMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {} + public EMA_Series(TSeries source, int period) : this(source, period, false, true) {} + public EMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {} + + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) { + if (update) { + _lastema = _oldema; + _sum = _oldsum; + } + else { + _oldema = _lastema; + _oldsum = _sum; + _len++; + } + + double _ema = 0; + if (_period == 0) { + _k = 2.0 / (_len + 1); + } + + if (Count == 0) { + _ema = _sum = TValue.v; + } + else if (_len <= _period && _useSMA && _period != 0) { + _sum += TValue.v; + if (_period != 0 && _len > _period) { + _sum -= _data[Count - _period - (update ? 1 : 0)].v; + } + + _ema = _sum / Math.Min(_len, _period); + } + else { + _ema = _k * (TValue.v - _lastema) + _lastema; + } + + _lastema = double.IsNaN(_ema) ? _lastema : _ema; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _ema); + return base.Add(res, update); + } + +//variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _sum = _oldsum = _lastema = _oldema = 0; + _len = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/ENTROPY_Series.cs b/Calculations/_Updated/ENTROPY_Series.cs new file mode 100644 index 00000000..4abd1239 --- /dev/null +++ b/Calculations/_Updated/ENTROPY_Series.cs @@ -0,0 +1,90 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Linq; + +/* +ENTROPY: + Introduced by Claude Shannon in 1948, entropy measures the unpredictability + of the data, or equivalently, of its average information. + +Calculation: + P = close / Σ(close) + ENTROPY = Σ(-P * Log(P) / Log(base)) + +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 + + */ + +public class ENTROPY_Series : TSeries { + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private readonly double _logbase; + private readonly System.Collections.Generic.List _buffer = new(); + private readonly System.Collections.Generic.List _buff2 = new(); + + //core constructors + public ENTROPY_Series(int period, double logbase, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + _logbase = logbase; + Name = $"ENTROPY({period})"; + } + public ENTROPY_Series(TSeries source, int period, double logbase, bool useNaN) : this(period, logbase, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public ENTROPY_Series() : this(period: 0, logbase: 2.0, useNaN: false) { } + public ENTROPY_Series(int period) : this(period: period, logbase: 2.0, useNaN: false) { } + public ENTROPY_Series(TBars source) : this(source.Close, period: 0, logbase: 2.0, useNaN: false) { } + public ENTROPY_Series(TBars source, int period) : this(source.Close, period, logbase: 2.0, useNaN: false) { } + public ENTROPY_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, logbase: 2.0, useNaN: useNaN) { } + public ENTROPY_Series(TSeries source) : this(source, period: 0, logbase: 2.0, useNaN: false) { } + public ENTROPY_Series(TSeries source, int period) : this(source: source, period: period, logbase: 2.0, useNaN: false) { } + public ENTROPY_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, logbase: 2.0, useNaN: useNaN) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN), update); + } + BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update); + double _sum = _buffer.Sum(); + double _pp = this._buffer[^1] / _sum; + double _ppp = -_pp * Math.Log(_pp) / Math.Log(this._logbase); + BufferTrim(_buff2, _ppp, _period, update); + double _entp = _buff2.Sum(); + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _entp); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + _buff2.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/FWMA_Series.cs b/Calculations/_Updated/FWMA_Series.cs new file mode 100644 index 00000000..fb50117c --- /dev/null +++ b/Calculations/_Updated/FWMA_Series.cs @@ -0,0 +1,100 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Numerics; +using System.Linq; + +/* +FWMA: Fibonacci's Weighted Moving Average is similar to a Weighted Moving Average + (WMA) where the weights are based on the Fibonacci Sequence. + + */ +public class FWMA_Series : TSeries { + private readonly List _buffer = new(); + private List _weights = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + protected int _len; + + public FWMA_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"FWMA({period})"; + _len = 0; + _weights = CalculateWeights(_period); + } + + public FWMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + + public FWMA_Series() : this(period: 0, useNaN: false) { } + public FWMA_Series(int period) : this(period: period, useNaN: false) { } + public FWMA_Series(TBars source) : this(source.Close, 0, false) { } + public FWMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public FWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public FWMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update); + if (_period == 0) { + _len++; + _weights = CalculateWeights(_len); + } + double _fwma = 0; + double totalWeights = _weights.Sum(); + object lockObj = new object(); + Parallel.For(0, _buffer.Count, i => + { + double temp = _buffer[i] * _weights[i]; + lock (lockObj) { _fwma += temp; } + }); + _fwma /= totalWeights; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _fwma); + return base.Add(res, update); + } + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + private static List CalculateWeights(int period) { + //to prevent overflow, max period can be no more than 1476 + period = (period > 1476) ? 1476 : period; + List weights = new List(period); + BigInteger a = 0; + BigInteger b = 1; + for (int i = 0; i < period; i++) { + BigInteger temp = a; + a = b; + b = temp + b; + weights.Add((double)Decimal.Parse(a.ToString())); + } + return weights; + } + + public override void Reset() { + _weights = CalculateWeights(_period); + _buffer.Clear(); + } +} diff --git a/Calculations/_Updated/HEMA_Series.cs b/Calculations/_Updated/HEMA_Series.cs new file mode 100644 index 00000000..84d292bf --- /dev/null +++ b/Calculations/_Updated/HEMA_Series.cs @@ -0,0 +1,116 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +HEMA: Hull-EMA Moving Average - a hybrid indicator + Modified HUll Moving Average; instead of using WMA (Weighted MA) for calculation, + 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 : TSeries { + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private double _k1, _k2, _k3; + private int _len; + private double _lastema1, _oldema1; + private double _lastema2, _oldema2; + private double _lasthema, _oldhema; + + //core constructors + public HEMA_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"HEMA({period})"; + CalculateK(_period, out _k1, out _k2, out _k3); + _len = 0; + _lastema1 = _oldema1 = _lastema2 = _oldema2 = _lasthema = _oldhema = 0; + } + public HEMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public HEMA_Series() : this(period: 0, useNaN: false) { } + public HEMA_Series(int period) : this(period: period, useNaN: false) { } + public HEMA_Series(TBars source) : this(source.Close, 0, false) { } + public HEMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public HEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public HEMA_Series(TSeries source) : this(source, 0, false) { } + public HEMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (update) { + _lastema1 = _oldema1; + _lastema2 = _oldema2; + _lasthema = _oldhema; + } + else { + _oldema1 = _lastema1; + _oldema2 = _lastema2; + _oldhema = _lasthema; + } + double _ema1, _ema2, _hema; + if (_period == 0) { + _len++; + CalculateK(_len, out _k1, out _k2, out _k3); + } + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, double.NaN), update); + } else if (this.Count == 0) { + _ema1 = _ema2 = _hema = TValue.v; + } + else { + _ema1 = _k1 * (TValue.v - _lastema1) + _lastema1; + _ema2 = _k2 * (TValue.v - _lastema2) + _lastema2; + _hema = _k3 * (((2 * _ema1) - _ema2) - _lasthema) + _lasthema; + } + + _lastema1 = _ema1; + _lastema2 = _ema2; + _lasthema = _hema; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hema); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _lastema1 = _lastema2 = _lasthema = 0; + _oldema1 = _oldema2 = _oldhema = 0; + _len = 0; + } + + public static void CalculateK(int len, out double k1, out double k2, out double k3) { + k1 = 8 / (double)(len + 7); + k2 = 3 / (double)(len + 2); + k3 = 2 / Math.Sqrt(len + 3); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/HMA_Series.cs b/Calculations/_Updated/HMA_Series.cs new file mode 100644 index 00000000..3631acf4 --- /dev/null +++ b/Calculations/_Updated/HMA_Series.cs @@ -0,0 +1,91 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +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. + +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 { + protected int _period, _period2, _psqrt; + protected readonly bool _NaN; + protected readonly TSeries _data; + protected WMA_Series _wma1, _wma2, _wma3; + + //core constructors + public HMA_Series(int period, bool useNaN) : base() { + _period = period; + _period2 = period /2; + _psqrt = (int)Math.Sqrt(period); + _NaN = useNaN; + _wma1 = new(Math.Max(_period2,1), false); + _wma2 = new(Math.Max(_period,1), false); + _wma3 = new(Math.Max(_psqrt,1), useNaN); + Name = $"HMA({period})"; + } + public HMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public HMA_Series() : this(period: 0, useNaN: false) { } + public HMA_Series(int period) : this(period: period, useNaN: false) { } + public HMA_Series(TBars source) : this(source.Close, 0, false) { } + public HMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public HMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public HMA_Series(TSeries source) : this(source, 0, false) { } + public HMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (_period == 0) { + _wma1.Len = this.Count / 2; + _wma2.Len = this.Count; + _wma1.Len = (int)Math.Sqrt(this.Count); + } + double _w1 = _wma1.Add(TValue, update).v; + double _w2 = _wma2.Add(TValue, update).v; + double _hma = _wma3.Add((2 * _w1) - _w2, update).v; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hma); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _wma1.Reset(); + _wma2.Reset(); + _wma3.Reset(); + } +} \ No newline at end of file diff --git a/Calculations/Trends/JMA_Series.cs b/Calculations/_Updated/JMA_Series.cs similarity index 54% rename from Calculations/Trends/JMA_Series.cs rename to Calculations/_Updated/JMA_Series.cs index f3d221a3..bfa9f445 100644 --- a/Calculations/Trends/JMA_Series.cs +++ b/Calculations/_Updated/JMA_Series.cs @@ -1,5 +1,6 @@ namespace QuanTAlib; using System; +using System.Collections.Generic; using System.Linq; /* @@ -18,38 +19,51 @@ Issues: 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 { + */ + +public class JMA_Series : TSeries { + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; private readonly System.Collections.Generic.List volty_short = new(); private readonly System.Collections.Generic.List vsum_buff = new(); private readonly double pr; - public TSeries mma1 { get; } - public TSeries mma2 { get; } - private double upperBand, lowerBand, vsum, Kv; private double prev_ma1, prev_det0, prev_det1, prev_vsum, prev_jma; private double p_upperBand, p_lowerBand, p_Kv, p_prev_ma1, p_prev_det0, p_prev_det1, p_prev_vsum, p_prev_jma; private readonly int _voltyS, _voltyL; - public JMA_Series(TSeries source, int period, double phase = 0.0, int vshort = 10, int vlong = 65, bool useNaN = false) : base(source, period, useNaN) { + //core constructors + public JMA_Series(int period, double phase, int vshort, int vlong, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"JMA({period})"; upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = 0.0; - - Kv = 0; - pr = (phase * 0.01) + 1.5; if (phase < -100) { pr = 0.5; } if (phase > 100) { pr = 2.5; } _voltyS = vshort; _voltyL = vlong; - mma1 = new(); - mma2 = new(); - - if (base._data.Count > 0) { base.Add(base._data); } } - public override void Add((System.DateTime t, double v) TValue, bool update) { - double del1 = 0.0, del2 = 0.0; + public JMA_Series(TSeries source, int period, double phase, int vshort, int vlong, bool useNaN) : this(period, phase, vshort, vlong, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public JMA_Series() : this(period: 0, phase: 0, vshort:10, vlong:65, useNaN: false) { } + public JMA_Series(int period) : this(period: period, phase: 0, vshort: 10, vlong: 65, useNaN: false) { } + public JMA_Series(TBars source) : this(source.Close, period:0, phase:0.0, vshort:10, vlong:65, useNaN:false) { } + public JMA_Series(TBars source, int period) : this(source.Close, period, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { } + public JMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, phase: 0.0, vshort: 10, vlong: 65, useNaN: useNaN) { } + public JMA_Series(TSeries source) : this(source, period:0, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { } + public JMA_Series(TSeries source, int period) : this(source: source, period: period, phase: 0.0, vshort: 10, vlong: 65, useNaN: false) { } + public JMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, phase: 0.0, vshort: 10, vlong: 65, useNaN: useNaN) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { if (this.Count == 0) { prev_ma1 = prev_jma = TValue.v; } if (update) { upperBand = p_upperBand; @@ -72,9 +86,13 @@ public class JMA_Series : Single_TSeries_Indicator { p_prev_jma = prev_jma; } + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, double.NaN),update); + } + // from Tvalue to volty - del1 = TValue.v - upperBand; - del2 = TValue.v - lowerBand; + double del1 = TValue.v - upperBand; + double del2 = TValue.v - lowerBand; upperBand = (del1 > 0) ? TValue.v : TValue.v - (Kv * del1); lowerBand = (del2 < 0) ? TValue.v : TValue.v - (Kv * del2); double volty = 0; @@ -96,7 +114,7 @@ public class JMA_Series : Single_TSeries_Indicator { /// from avolty to rolty double rvolty = (avolty != 0) ? volty / avolty : 0; - double len1 = (Math.Log(Math.Sqrt(_p)) / Math.Log(2.0)) + 2; + double len1 = (Math.Log(Math.Sqrt(_period)) / Math.Log(2.0)) + 2; if (len1 < 0) { len1 = 0; } double pow1 = Math.Max(len1 - 2.0, 0.5); @@ -105,23 +123,45 @@ public class JMA_Series : Single_TSeries_Indicator { //// from rvolty to second smoothing double pow2 = Math.Pow(rvolty, pow1); - double beta = 0.45 * (_p - 1) / (0.45 * (_p - 1) + 2); + double beta = 0.45 * (_period - 1) / (0.45 * (_period - 1) + 2); Kv = Math.Pow(beta, Math.Sqrt(pow2)); double alpha = Math.Pow(beta, pow2); double ma1 = (1 - alpha) * TValue.v + alpha * prev_ma1; prev_ma1 = ma1; - mma1.Add(ma1); double det0 = (1 - beta) * (TValue.v - ma1) + beta * prev_det0; prev_det0 = det0; double ma2 = ma1 + pr * det0; - mma2.Add(ma2); double det1 = ((1 - alpha) * (1 - alpha) * (ma2 - prev_jma)) + (alpha * alpha * prev_det1); prev_det1 = det1; double jma = prev_jma + det1; prev_jma = jma; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : jma); + return base.Add(res, update); + } - base.Add((TValue.t, jma), update, _NaN); + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + upperBand = lowerBand = prev_ma1 = prev_det0 = prev_det1 = prev_vsum = prev_jma = Kv = 0.0; } } \ No newline at end of file diff --git a/Calculations/_Updated/KAMA_Series.cs b/Calculations/_Updated/KAMA_Series.cs new file mode 100644 index 00000000..87200bef --- /dev/null +++ b/Calculations/_Updated/KAMA_Series.cs @@ -0,0 +1,114 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +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. + + KAMA[i] = KAMA[i-1] + SC * ( price - KAMA[i-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 : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + private double _lastkama, _lastlastkama; + private int _len; + private readonly double _scFast, _scSlow; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public KAMA_Series(int period, int fast, int slow, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + _len = 0; + _scFast = 2.0 / (((period < fast) ? period : fast) + 1); + _scSlow = 2.0 / (slow + 1); + _lastkama = _lastlastkama = 0; + Name = $"KAMA({period})"; + } + public KAMA_Series(TSeries source, int period, int fast, int slow, bool useNaN) : this(period, fast, slow, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public KAMA_Series() : this(period: 0, fast: 2, slow: 30, useNaN: false) { } + public KAMA_Series(int period) : this(period: period, fast: 2, slow: 30, useNaN: false) { } + public KAMA_Series(TBars source) : this(source.Close, period: 0, fast: 2, slow: 30, useNaN: false) { } + public KAMA_Series(TBars source, int period) : this(source.Close, period: period, fast: 2, slow: 30, useNaN: false) { } + public KAMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period: period, fast: 2, slow: 30, useNaN: useNaN) { } + public KAMA_Series(TSeries source) : this(source, period: 0, fast: 2, slow: 30, useNaN: false) { } + public KAMA_Series(TSeries source, int period) : this(source: source, period: period, fast: 2, slow: 30, useNaN: false) { } + public KAMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, fast: 2, slow: 30, useNaN: useNaN) { } + public KAMA_Series(TSeries source, int period, int fast, int slow) : this(source: source, period: period, fast: fast, slow: slow, useNaN: false) { } + + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN), update); + } + + if (update) { _lastkama = _lastlastkama; } + else { _lastlastkama = _lastkama; } + BufferTrim(buffer: _buffer, value: TValue.v, period: _period + 1, update: update); + + double _kama = 0; + if (this.Count < _period) { _kama = TValue.v; } + else { + double _change = Math.Abs(_buffer[^1] - _buffer[(_buffer.Count > _period + 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))); + } + _len++; + _lastkama = _kama; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _kama); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + _len = 0; + _lastkama = _lastlastkama = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/KURTOSIS_Series.cs b/Calculations/_Updated/KURTOSIS_Series.cs new file mode 100644 index 00000000..6c1b48c6 --- /dev/null +++ b/Calculations/_Updated/KURTOSIS_Series.cs @@ -0,0 +1,99 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Linq; + +/* +KURTOSIS: 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. + + The normal curve is called Mesokurtic curve. If the curve of a distribution is + more outlier prone (or heavier-tailed) than a normal or mesokurtic curve then + it is referred to as a Leptokurtic curve. If a curve is less outlier prone (or + lighter-tailed) than a normal curve, it is called as a platykurtic curve. + +Calculation: + sum4 = Σ(close-SMA)^4 + sum2 = (Σ(close-SMA)^2)^2 + KURTOSIS = length * (sum4/sum2) + +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/ + + */ + +public class KURTOSIS_Series : TSeries { + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private readonly System.Collections.Generic.List _buffer = new(); + + //core constructors + public KURTOSIS_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"KURTOSIS({period})"; + } + public KURTOSIS_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public KURTOSIS_Series() : this(period: 0, useNaN: false) { } + public KURTOSIS_Series(int period) : this(period: period, useNaN: false) { } + public KURTOSIS_Series(TSeries source) : this(source, period: 0, useNaN: false) { } + public KURTOSIS_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN), update); + } + + BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update); + double _n = _buffer.Count; + double _avg = _buffer.Average(); + + double _s2 = 0; + double _s4 = 0; + for (int i = 0; i < this._buffer.Count; i++) { + _s2 += (_buffer[i] - _avg) * (_buffer[i] - _avg); + _s4 += (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg) * (_buffer[i] - _avg); + } + + double _Vx = _s2 / (_n - 1); + double _kurt = (_n > 3) ? + (_n * (_n + 1) * _s4) / (_Vx * _Vx * (_n - 3) * (_n - 1) * (_n - 2)) - (3 * (_n - 1) * (_n - 1) / ((_n - 2) * (_n - 3))) //using Sheskin Algo + : (_s2 * _s2) / _n - 3; //using Snedecor and Cochran (1967) algo + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _kurt); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/MAD_Series.cs b/Calculations/_Updated/MAD_Series.cs new file mode 100644 index 00000000..e1f358cd --- /dev/null +++ b/Calculations/_Updated/MAD_Series.cs @@ -0,0 +1,82 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +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 + +Sources: + https://en.wikipedia.org/wiki/Average_absolute_deviation + + */ + +public class MAD_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public MAD_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"MAD({period})"; + } + public MAD_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public MAD_Series() : this(period: 0, useNaN: false) { } + public MAD_Series(int period) : this(period: period, useNaN: false) { } + public MAD_Series(TBars source) : this(source.Close, 0, false) { } + public MAD_Series(TBars source, int period) : this(source.Close, period, false) { } + public MAD_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public MAD_Series(TSeries source) : this(source, 0, false) { } + public MAD_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + double _mad = 0; + for (int i = 0; i < _buffer.Count; i++) { _mad += Math.Abs(_buffer[i] - _sma); } + _mad /= this._buffer.Count; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mad); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/MAPE_Series.cs b/Calculations/_Updated/MAPE_Series.cs new file mode 100644 index 00000000..776a9a12 --- /dev/null +++ b/Calculations/_Updated/MAPE_Series.cs @@ -0,0 +1,88 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +MAPE: Mean Absolute Percentage Error + Measures the size of the error in percentage terms + +Calculation: + MAPE = Σ(|close – SMA| / |close|) / n + +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 + + */ + +public class MAPE_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public MAPE_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"MAPE({period})"; + } + public MAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public MAPE_Series() : this(period: 0, useNaN: false) { } + public MAPE_Series(int period) : this(period: period, useNaN: false) { } + public MAPE_Series(TBars source) : this(source.Close, 0, false) { } + public MAPE_Series(TBars source, int period) : this(source.Close, period, false) { } + public MAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public MAPE_Series(TSeries source) : this(source, 0, false) { } + public MAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + double _mape = 0; + for (int i = 0; i < _buffer.Count; i++) { + _mape += (_buffer[i] != 0) ? Math.Abs(_buffer[i] - _sma) / Math.Abs(_buffer[i]) : double.PositiveInfinity; + } + _mape /= (_buffer.Count > 0) ? _buffer.Count : 1; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mape); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/MAX_Series.cs b/Calculations/_Updated/MAX_Series.cs new file mode 100644 index 00000000..0eae2b6f --- /dev/null +++ b/Calculations/_Updated/MAX_Series.cs @@ -0,0 +1,71 @@ +using System.Linq; + +namespace QuanTAlib; +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 : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public MAX_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"MAX({period})"; + } + public MAX_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public MAX_Series() : this(period: 0, useNaN: false) { } + public MAX_Series(int period) : this(period: period, useNaN: false) { } + public MAX_Series(TBars source) : this(source.Close, 0, false) { } + public MAX_Series(TBars source, int period) : this(source.Close, period, false) { } + public MAX_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public MAX_Series(TSeries source) : this(source, 0, false) { } + public MAX_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _max= _buffer.Max(); + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _max); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/MEDIAN_Series.cs b/Calculations/_Updated/MEDIAN_Series.cs new file mode 100644 index 00000000..18e46c67 --- /dev/null +++ b/Calculations/_Updated/MEDIAN_Series.cs @@ -0,0 +1,89 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +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. + + 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 + +Sources: + https://corporatefinanceinstitute.com/resources/knowledge/other/median/ + https://en.wikipedia.org/wiki/Median + + */ + +public class MEDIAN_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public MEDIAN_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"MEDIAN({period})"; + } + public MEDIAN_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public MEDIAN_Series() : this(period: 0, useNaN: false) { } + public MEDIAN_Series(int period) : this(period: period, useNaN: false) { } + public MEDIAN_Series(TBars source) : this(source.Close, 0, false) { } + public MEDIAN_Series(TBars source, int period) : this(source.Close, period, false) { } + public MEDIAN_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public MEDIAN_Series(TSeries source) : this(source, 0, false) { } + public MEDIAN_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + System.Collections.Generic.List _s = new(this._buffer); + _s.Sort(); + int _p1 = _s.Count / 2; + int _p2 = Math.Max(0, (_s.Count / 2) - 1); + double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _med); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/MIDPOINT_Series.cs b/Calculations/_Updated/MIDPOINT_Series.cs new file mode 100644 index 00000000..686f9825 --- /dev/null +++ b/Calculations/_Updated/MIDPOINT_Series.cs @@ -0,0 +1,75 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +MIDPOINT: Midpoint value (max+min)/2 in the given period in the series. + If period = 0 => period = full length of the series + +Sources: + https://thefaqblog.com/what-is-the-midpoint-in-statistics/ + + */ + +public class MIDPOINT_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public MIDPOINT_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"MIDPOINT({period})"; + } + public MIDPOINT_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public MIDPOINT_Series() : this(period: 0, useNaN: false) { } + public MIDPOINT_Series(int period) : this(period: period, useNaN: false) { } + public MIDPOINT_Series(TBars source) : this(source.Close, 0, false) { } + public MIDPOINT_Series(TBars source, int period) : this(source.Close, period, false) { } + public MIDPOINT_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public MIDPOINT_Series(TSeries source) : this(source, 0, false) { } + public MIDPOINT_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _max= _buffer.Max(); + double _min = _buffer.Min(); + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : (_max+_min)*0.5); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/MIN_Series.cs b/Calculations/_Updated/MIN_Series.cs new file mode 100644 index 00000000..30b68fae --- /dev/null +++ b/Calculations/_Updated/MIN_Series.cs @@ -0,0 +1,71 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +MIN - Minimum value in the given period in the series. + If period = 0 => period = full length of the series + + */ + +public class MIN_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public MIN_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"MAX({period})"; + } + public MIN_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public MIN_Series() : this(period: 0, useNaN: false) { } + public MIN_Series(int period) : this(period: period, useNaN: false) { } + public MIN_Series(TBars source) : this(source.Close, 0, false) { } + public MIN_Series(TBars source, int period) : this(source.Close, period, false) { } + public MIN_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public MIN_Series(TSeries source) : this(source, 0, false) { } + public MIN_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _max= _buffer.Min(); + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _max); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/MSE_Series.cs b/Calculations/_Updated/MSE_Series.cs new file mode 100644 index 00000000..18406554 --- /dev/null +++ b/Calculations/_Updated/MSE_Series.cs @@ -0,0 +1,79 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +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 + + */ + +public class MSE_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public MSE_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"MSE({period})"; + } + public MSE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public MSE_Series() : this(period: 0, useNaN: false) { } + public MSE_Series(int period) : this(period: period, useNaN: false) { } + public MSE_Series(TBars source) : this(source.Close, 0, false) { } + public MSE_Series(TBars source, int period) : this(source.Close, period, false) { } + public MSE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public MSE_Series(TSeries source) : this(source, 0, false) { } + public MSE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + double _mse = 0; + for (int i = 0; i < _buffer.Count; i++) { _mse += (_buffer[i] - _sma) * (_buffer[i] - _sma); } + _mse /= this._buffer.Count; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mse); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/RMA_Series.cs b/Calculations/_Updated/RMA_Series.cs new file mode 100644 index 00000000..b5be9d9c --- /dev/null +++ b/Calculations/_Updated/RMA_Series.cs @@ -0,0 +1,119 @@ +namespace QuanTAlib; + +using System; +using System.Linq; + +/* +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. + +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 + +Issues: + Pandas-TA library calculates RMA using straight Exponential Weighted Mean: + pandas.ewm().mean() and returns incorrect first (period) of bars compared to + published formula. This implementation passess the validation test in Wilder's book. + + */ + +public class RMA_Series : TSeries { + private double _k; + private double _lastrma, _oldrma; + private double _sum, _oldsum; + private readonly bool _useSMA; + private int _len; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + +//core constructor + public RMA_Series(int period, bool useNaN, bool useSMA) : base() { + _period = period; + _NaN = useNaN; + _useSMA = useSMA; + Name = $"RMA({period})"; + _k = 1.0 / (double)(this._period); + _len = 0; + _sum = _oldsum = _lastrma = _oldrma = 0; + } + //generic constructors (source) + + public RMA_Series() : this(0, false, true) {} + public RMA_Series(int period) : this(period, false, true) {} + public RMA_Series(TBars source) : this(source.Close, 0, false) {} + public RMA_Series(TBars source, int period) : this(source.Close, period, false) {} + public RMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {} + public RMA_Series(TSeries source, int period) : this(source, period, false, true) {} + public RMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {} + public RMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + +// core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) { + if (update) { + _lastrma = _oldrma; + _sum = _oldsum; + } + else { + _oldrma = _lastrma; + _oldsum = _sum; + _len++; + } + + double _rma = 0; + if (_period == 0) { + _k = 1.0 / (double)(this._len); + } + + if (Count == 0) { + _rma = _sum = TValue.v; + + } else if (_len <= _period && _useSMA && _period != 0) { + _sum += TValue.v; + if (_period != 0 && _len > _period) { + _sum -= _data[Count - _period - (update ? 1 : 0)].v; + } + _rma = _sum / Math.Min(_len, _period); + } + else { + _rma = _k * (TValue.v - _lastrma) + _lastrma; + } + + _lastrma = double.IsNaN(_rma) ? _lastrma : _rma; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _rma); + return base.Add(res, update); + } + +//variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _sum = _oldsum = _lastrma = _oldrma = 0; + _len = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/RSI_Series.cs b/Calculations/_Updated/RSI_Series.cs new file mode 100644 index 00000000..a1cd561e --- /dev/null +++ b/Calculations/_Updated/RSI_Series.cs @@ -0,0 +1,123 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +RSI: Relative Strength Index + Created by J. Welles Wilder, the Relative Strength Index measures strength + of the winning/losing streak over N lookback periods on a scale of 0 to 100, + to depict overbought and oversold conditions. + +Sources: + https://www.investopedia.com/terms/r/rsi.asp + + */ + +public class RSI_Series : TSeries { + private readonly System.Collections.Generic.List _gain = new(); + private readonly System.Collections.Generic.List _loss = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private double _avgGain, _avgLoss, _lastValue; + private double _avgGain_o, _avgLoss_o, _lastValue_o; + private int i; + + //core constructors + public RSI_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"RSI({period})"; + i = 0; + } + public RSI_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public RSI_Series() : this(period: 0, useNaN: false) { } + public RSI_Series(int period) : this(period: period, useNaN: false) { } + public RSI_Series(TBars source) : this(source.Close, 0, false) { } + public RSI_Series(TBars source, int period) : this(source.Close, period, false) { } + public RSI_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public RSI_Series(TSeries source) : this(source, 0, false) { } + public RSI_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + + double _rsi = 0; + if (update) { + _lastValue = _lastValue_o; + _avgGain = _avgGain_o; + _avgLoss = _avgLoss_o; + } + else { + _lastValue_o = _lastValue; + _avgGain_o = _avgGain; + _avgLoss_o = _avgLoss; + } + + if (i == 0) { _lastValue = TValue.v; } + + double _gainval = (TValue.v > _lastValue) ? TValue.v - _lastValue : 0; + BufferTrim(_gain, _gainval, _period, update); + double _lossval = (TValue.v < _lastValue) ? _lastValue - TValue.v : 0; + BufferTrim(_loss, _lossval, _period, update); + _lastValue = TValue.v; + + // calculate RSI + if (i > _period && _period != 0) { + _avgGain = ((_avgGain * (_period - 1)) + _gain[^1]) / _period; + _avgLoss = ((_avgLoss * (_period - 1)) + _loss[^1]) / _period; + if (_avgLoss > 0) { + double rs = _avgGain / _avgLoss; + _rsi = 100 - (100 / (1 + rs)); + } + else { _rsi = 100; } + } + // initialize average gain + else { + double _sumGain = 0; + for (int p = 0; p < _gain.Count; p++) { _sumGain += _gain[p]; } + double _sumLoss = 0; + for (int p = 0; p < _loss.Count; p++) { _sumLoss += _loss[p]; } + + _avgGain = _sumGain / _gain.Count; + _avgLoss = _sumLoss / _loss.Count; + + _rsi = (_avgLoss > 0) ? 100 - (100 / (1 + (_avgGain / _avgLoss))) : 100; + } + if (!update) { i++; } + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _rsi); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + i = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/SDEV_Series.cs b/Calculations/_Updated/SDEV_Series.cs new file mode 100644 index 00000000..90d269cd --- /dev/null +++ b/Calculations/_Updated/SDEV_Series.cs @@ -0,0 +1,85 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +SDEV: 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 + +Remark: + SDEV (Population Standard Deviation) is also known as a biased/uncorrected Standard Deviation. + For unbiased version that uses Bessel's correction, use SDEV instead. + + */ + +public class SDEV_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public SDEV_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"SDEV({period})"; + } + public SDEV_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public SDEV_Series() : this(period: 0, useNaN: false) { } + public SDEV_Series(int period) : this(period: period, useNaN: false) { } + public SDEV_Series(TBars source) : this(source.Close, 0, false) { } + public SDEV_Series(TBars source, int period) : this(source.Close, period, false) { } + public SDEV_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public SDEV_Series(TSeries source) : this(source, 0, false) { } + public SDEV_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + double _var = 0; + for (int i = 0; i < _buffer.Count; i++) { _var += (_buffer[i] - _sma) * (_buffer[i] - _sma); } + _var /= this._buffer.Count; + double _sdev = Math.Sqrt(_var); + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sdev); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/SMAPE_Series.cs b/Calculations/_Updated/SMAPE_Series.cs new file mode 100644 index 00000000..7ab08d6a --- /dev/null +++ b/Calculations/_Updated/SMAPE_Series.cs @@ -0,0 +1,80 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +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 + + */ + +public class SMAPE_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public SMAPE_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"SMAPE({period})"; + } + public SMAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public SMAPE_Series() : this(period: 0, useNaN: false) { } + public SMAPE_Series(int period) : this(period: period, useNaN: false) { } + public SMAPE_Series(TBars source) : this(source.Close, 0, false) { } + public SMAPE_Series(TBars source, int period) : this(source.Close, period, false) { } + public SMAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public SMAPE_Series(TSeries source) : this(source, 0, false) { } + public SMAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + + double _smape = 0; + for (int i = 0; i < _buffer.Count; i++) { _smape += Math.Abs(_buffer[i] - _sma) / (Math.Abs(_buffer[i]) + Math.Abs(_sma)); } + _smape /= this._buffer.Count; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _smape); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/SMA_Series.cs b/Calculations/_Updated/SMA_Series.cs new file mode 100644 index 00000000..30ccc4ba --- /dev/null +++ b/Calculations/_Updated/SMA_Series.cs @@ -0,0 +1,99 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +SMA: Simple Moving Average + 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 (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 : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + + private double _sum, _oldsum; + private readonly int _period; + private readonly TSeries _data; + protected readonly bool _NaN; + + //core constructor + public SMA_Series(int period, bool useNaN) : base() { + _period = Math.Max(0, period); + _NaN = useNaN; + Name = $"SMA({period})"; + _sum = _oldsum = 0; + } + public SMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public SMA_Series() : this(0, false) {} + public SMA_Series(int period) : this(period, false) {} + public SMA_Series(TBars source) : this(source.Close, 0, false) {} + public SMA_Series(TBars source, int period) : this(source.Close, period, false) {} + public SMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {} + public SMA_Series(TSeries source) : this(source, 0, false) {} + public SMA_Series(TSeries source, int period) : this(source, period, false) {} + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) { + if (double.IsNaN(TValue.v)) { return (TValue.t, double.NaN); + } else { + if (update && _buffer.Count > 0) { + _sum -= _buffer[^1]; + _buffer[^1] = TValue.v; + _oldsum = _sum; + } + else { + _buffer.Add(TValue.v); + _oldsum = _sum; + } + + _sum += TValue.v; + if (_period != 0 && _buffer.Count > _period) { + _sum -= _buffer[0]; + _buffer.RemoveAt(0); + } + } + + double _div = _period == 0 ? _buffer.Count : Math.Min(_buffer.Count, _period); + var _sma = _sum / _div; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _sma); + return base.Add(res, update); + } + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + + //reset calculation + public override void Reset() { + _sum = _oldsum = 0; + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/SMMA_Series.cs b/Calculations/_Updated/SMMA_Series.cs new file mode 100644 index 00000000..50bed0ba --- /dev/null +++ b/Calculations/_Updated/SMMA_Series.cs @@ -0,0 +1,96 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Linq; + +/* +SMMA: Smoothed Moving Average + The Smoothed Moving Average (SMMA) is a combination of a SMA and an EMA. It gives the recent prices + an equal weighting as the historic prices as it takes all available price data into account. + The main advantage of a smoothed moving average is that it removes short-term fluctuations. + + SMMA(i) = (SMMA-1*(N-1) + CLOSE (i)) / N + +Sources: + https://blog.earn2trade.com/smoothed-moving-average + https://guide.traderevolution.com/traderevolution/mobile-applications/phone/android/technical-indicators/moving-averages/smma-smoothed-moving-average + https://www.chartmill.com/documentation/technical-analysis-indicators/217-MOVING-AVERAGES-%7C-The-Smoothed-Moving-Average-%28SMMA%29 + + */ + +public class SMMA_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private double _lastsmma, _lastlastsmma; + + //core constructors + public SMMA_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"SMMA({period})"; + } + public SMMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public SMMA_Series() : this(period: 0, useNaN: false) { } + public SMMA_Series(int period) : this(period: period, useNaN: false) { } + public SMMA_Series(TBars source) : this(source.Close, 0, false) { } + public SMMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public SMMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public SMMA_Series(TSeries source) : this(source, 0, false) { } + public SMMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, double.NaN),update); + } + + double _smma = 0; + if (update) { this._lastsmma = this._lastlastsmma; } + + if (this.Count < this._period) { + BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update); + _smma = _buffer.Average(); + } + else { + _smma = ((_lastsmma * (_period - 1)) + TValue.v) / _period; + } + + this._lastlastsmma = this._lastsmma; + this._lastsmma = _smma; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _smma); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + this._lastsmma = this._lastlastsmma = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/SSDEV_Series.cs b/Calculations/_Updated/SSDEV_Series.cs new file mode 100644 index 00000000..e295199a --- /dev/null +++ b/Calculations/_Updated/SSDEV_Series.cs @@ -0,0 +1,85 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +SSDEV: (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 + + */ + +public class SSDEV_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public SSDEV_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"SSDEV({period})"; + } + public SSDEV_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public SSDEV_Series() : this(period: 0, useNaN: false) { } + public SSDEV_Series(int period) : this(period: period, useNaN: false) { } + public SSDEV_Series(TBars source) : this(source.Close, 0, false) { } + public SSDEV_Series(TBars source, int period) : this(source.Close, period, false) { } + public SSDEV_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public SSDEV_Series(TSeries source) : this(source, 0, false) { } + public SSDEV_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + double _svar = 0; + for (int i = 0; i < this._buffer.Count; i++) { _svar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } + _svar /= (_buffer.Count > 1) ? _buffer.Count - 1 : 1; // Bessel's correction + double _ssdev = Math.Sqrt(_svar); + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _ssdev); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/SVAR_Series.cs b/Calculations/_Updated/SVAR_Series.cs new file mode 100644 index 00000000..4c4e0c8a --- /dev/null +++ b/Calculations/_Updated/SVAR_Series.cs @@ -0,0 +1,84 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +VAR: Population Variance + Population variance without Bessel's correction + +Sources: + https://en.wikipedia.org/wiki/Variance + Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction + +Remark: + VAR (Population Variance) is also known as a biased Sample Variance. For unbiased + sample variance use SVAR instead. + + */ + +public class SVAR_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public SVAR_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"SVAR({period})"; + } + public SVAR_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public SVAR_Series() : this(period: 0, useNaN: false) { } + public SVAR_Series(int period) : this(period: period, useNaN: false) { } + public SVAR_Series(TBars source) : this(source.Close, 0, false) { } + public SVAR_Series(TBars source, int period) : this(source.Close, period, false) { } + public SVAR_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public SVAR_Series(TSeries source) : this(source, 0, false) { } + public SVAR_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + double _svar = 0; + for (int i = 0; i < this._buffer.Count; i++) { _svar += (this._buffer[i] - _sma) * (this._buffer[i] - _sma); } + _svar /= (this._buffer.Count > 1) ? this._buffer.Count - 1 : 1; // Bessel's correction + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _svar); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/T3_Series.cs b/Calculations/_Updated/T3_Series.cs new file mode 100644 index 00000000..d9abbb65 --- /dev/null +++ b/Calculations/_Updated/T3_Series.cs @@ -0,0 +1,164 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Numerics; + +/* +T3: Tillson T3 Moving Average + Tim Tillson described it in "Technical Analysis of Stocks and Commodities", January 1998 in the + article "Better Moving Averages". Tillson’s moving average becomes a popular indicator of + technical analysis as it gets less lag with the price chart and its curve is considerably smoother. + +Sources: + https://technicalindicators.net/indicators-technical-analysis/150-t3-moving-average + http://www.binarytribune.com/forex-trading-indicators/t3-moving-average-indicator/ + */ + +public class T3_Series : TSeries { + private readonly double _k, _k1m, _c1, _c2, _c3, _c4; + private readonly System.Collections.Generic.List _buffer1 = new(); + private readonly System.Collections.Generic.List _buffer2 = new(); + private readonly System.Collections.Generic.List _buffer3 = new(); + private readonly System.Collections.Generic.List _buffer4 = new(); + private readonly System.Collections.Generic.List _buffer5 = new(); + private readonly System.Collections.Generic.List _buffer6 = new(); + private readonly bool _useSMA; + private double _lastema1, _lastema2, _lastema3, _lastema4, _lastema5, _lastema6; + private double _llastema1, _llastema2, _llastema3, _llastema4, _llastema5, _llastema6; + protected int _len; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public T3_Series(int period, double vfactor, bool useSMA, bool useNaN) : base() { + _period = period; + _len = 0; + _NaN = useNaN; + Name = $"T3({period})"; + _useSMA = useSMA; + double _a = vfactor; //0.7; //0.618 + _c1 = -_a * _a * _a; + _c2 = 3 * _a * _a + 3 * _a * _a * _a; + _c3 = -6 * _a * _a - 3 * _a - 3 * _a * _a * _a; + _c4 = 1 + 3 * _a + _a * _a * _a + 3 * _a * _a; + + _k = 2.0 / (_period + 1); + _k1m = 1.0 - _k; + _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = _lastema4 = _llastema4 = _lastema5 = _llastema5 = _lastema5 = _llastema5 = 0; + } + public T3_Series(TSeries source, int period, double vfactor, bool useSMA, bool useNaN) : this(period, vfactor, useSMA, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public T3_Series() : this(period: 0, vfactor: 0.7, useSMA: true, useNaN: false) { } + public T3_Series(int period) : this(period: period, vfactor: 0.7, useSMA: true, useNaN: false) { } + public T3_Series(TBars source) : this(source.Close, 0, vfactor: 0.7, useSMA: true, useNaN: false) { } + public T3_Series(TBars source, int period) : this(source.Close, period, vfactor: 0.7, useSMA: true, useNaN: false) { } + public T3_Series(TBars source, int period, bool useNaN) : this(source.Close, period, vfactor: 0.7, useSMA: true, useNaN: useNaN) { } + public T3_Series(TBars source, int period, double vfactor, bool useNaN) : this(source.Close, period, vfactor: vfactor, useSMA: true, useNaN: useNaN) { } + public T3_Series(TBars source, int period, bool useSMA, bool useNaN) : this(source.Close, period, vfactor: 0.7, useSMA: useSMA, useNaN: useNaN) { } + public T3_Series(TSeries source) : this(source, 0, vfactor: 0.7, useSMA: true, useNaN: false) { } + public T3_Series(TSeries source, int period) : this(source: source, period: period, vfactor: 0.7, useSMA: true, useNaN: false) { } + public T3_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, vfactor: 0.7, useSMA: true, useNaN: useNaN) { } + public T3_Series(TSeries source, int period, double vfactor) : this(source: source, period: period, vfactor: vfactor, useSMA: true, useNaN: false) { } + public T3_Series(TSeries source, int period, double vfactor, bool useNaN) : this(source: source, period: period, vfactor: vfactor, useSMA: true, useNaN: useNaN) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + double _ema1, _ema2, _ema3, _ema4, _ema5, _ema6; + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN),update); + } + + if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; _lastema4 = _llastema4; _lastema5 = _llastema5; _lastema6 = _llastema6; } + else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; _llastema4 = _lastema4; _llastema5 = _lastema5; _llastema6 = _lastema6; } + + if (_len == 0) { _lastema1 = _lastema2 = _lastema3 = _lastema4 = _lastema5 = _lastema6 = TValue.v; } + + + if ((_len < _period) && _useSMA) { + BufferTrim(_buffer1, TValue.v, _period, update); + _ema1 = 0; + for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; } + _ema1 /= _buffer1.Count; + + BufferTrim(_buffer2, _ema1, _period, update); + _ema2 = 0; + for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; } + _ema2 /= _buffer2.Count; + + BufferTrim(_buffer3, _ema2, _period, update); + _ema3 = 0; + for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; } + _ema3 /= _buffer3.Count; + + BufferTrim(_buffer4, _ema3, _period, update); + _ema4 = 0; + for (int i = 0; i < _buffer4.Count; i++) { _ema4 += _buffer4[i]; } + _ema4 /= _buffer4.Count; + + BufferTrim(_buffer5, _ema4, _period, update); + _ema5 = 0; + for (int i = 0; i < _buffer5.Count; i++) { _ema5 += _buffer5[i]; } + _ema5 /= _buffer5.Count; + + BufferTrim(_buffer6, _ema5, _period, update); + _ema6 = 0; + for (int i = 0; i < _buffer6.Count; i++) { _ema6 += _buffer6[i]; } + _ema6 /= _buffer6.Count; + } + 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); + _ema4 = (_ema3 * this._k) + (this._lastema4 * this._k1m); + _ema5 = (_ema4 * this._k) + (this._lastema5 * this._k1m); + _ema6 = (_ema5 * this._k) + (this._lastema6 * this._k1m); + } + _len++; + _lastema1 = _ema1; + _lastema2 = _ema2; + _lastema3 = _ema3; + _lastema4 = _ema4; + _lastema5 = _ema5; + _lastema6 = _ema6; + + double _T3 = _c1 * _ema6 + _c2 * _ema5 + _c3 * _ema4 + _c4 * _ema3; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _T3); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = _lastema4 = _llastema4 = _lastema5 = _llastema5 = _lastema5 = _llastema5 = 0; + _buffer1.Clear(); + _buffer2.Clear(); + _buffer3.Clear(); + _buffer4.Clear(); + _buffer5.Clear(); + _buffer6.Clear(); + _len = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/TBars.cs b/Calculations/_Updated/TBars.cs new file mode 100644 index 00000000..8387219d --- /dev/null +++ b/Calculations/_Updated/TBars.cs @@ -0,0 +1,126 @@ +namespace QuanTAlib; +using System; + +/* +TBars class - includes all series for common data used in indicators and other calculations. + Has a bit limited overloading and casting (compared to TSeries) + Includes Select(int) method to simplify choosing the most optimal data source for indicators + Includes the most basic pricing calcs: HL2, OC2, OHL3, HLC3, OHLC4, HLCC4 + (it is 'cheaper' to calculate them once during data capture than each time during data analysis) + + */ + +public class TBars : System.Collections.Generic.List<(DateTime t, double o, double h, double l, double c, double v)> +{ + public string Name { get; set; } + private readonly TSeries _open = new("open"); + private readonly TSeries _high = new("high"); + private readonly TSeries _low = new("low"); + private readonly TSeries _close = new("close"); + private readonly TSeries _volume = new("volume"); + private readonly TSeries _hl2 = new("HL2"); + private readonly TSeries _oc2 = new("OC2"); + private readonly TSeries _ohl3 = new("OHL3"); + private readonly TSeries _hlc3 = new("HLC3"); + private readonly TSeries _ohlc4 = new("OHLC4"); + private readonly TSeries _hlcc4 = new("HLCC4"); + + public TSeries Open => this._open; + public TSeries High => this._high; + public TSeries Low => this._low; + public TSeries Close => this._close; + public TSeries Volume => this._volume; + public TSeries HL2 => this._hl2; + public TSeries OC2 => this._oc2; + public TSeries OHL3 => this._ohl3; + public TSeries HLC3 => this._hlc3; + public TSeries OHLC4 => this._ohlc4; + public TSeries HLCC4 => this._hlcc4; + + public TBars() { } + + public TBars(string Name) { + this.Name = Name; + } + + public (DateTime t, double o, double h, double l, double c, double v) Last => this[^1]; + public TBars Tail(int count = 10) + { + TBars outBars = new(); + if (count > this.Count) { count = this.Count; } + for (int i = this.Count - count; i < this.Count; i++) { outBars.Add(this[i]); } + return outBars; + } + public TSeries Select(int source) + { + return source switch + { + 0 => _open, + 1 => _high, + 2 => _low, + 3 => _close, + 4 => _hl2, + 5 => _oc2, + 6 => _ohl3, + 7 => _hlc3, + 8 => _ohlc4, + _ => _hlcc4, + }; + } + public static string SelectStr(int source) + { + return source switch + { + 0 => "Open", + 1 => "High", + 2 => "Low", + 3 => "Close", + 4 => "HL2", + 5 => "OC2", + 6 => "OHL3", + 7 => "HLC3", + 8 => "OHLC4", + _ => "HLCC4", + }; + } + + public virtual (DateTime t, double o, double h, double l, double c, double v) Add((double o, double h, double l, double c, double v) p, bool update = false) => + Add((t: (this.Count == 0) ? DateTime.Today : this[^1].t.AddDays(1),p.o,p.h,p.l,p.c,p.v),update); + + public virtual (DateTime t, double o, double h, double l, double c, double v) Add(double o, double h, double l, double c, double v, bool update = false) => + Add((o,h,l,c,v),update); + + public virtual (DateTime t, double o, double h, double l, double c, double v) Add(DateTime t, double o, double h, double l, double c, double v, bool update = false) => + this.Add((t, o, h, l, c, v), update); + + public virtual (DateTime t, double o, double h, double l, double c, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) { + if (update) { this[^1] = TBar; } else { base.Add(TBar); } + + _open.Add((TBar.t, TBar.o), update); + _high.Add((TBar.t, TBar.h), update); + _low.Add((TBar.t, TBar.l), update); + _close.Add((TBar.t, TBar.c), update); + _volume.Add((TBar.t, TBar.v), update); + _hl2.Add((TBar.t, (TBar.h + TBar.l) * 0.5), update); + _oc2.Add((TBar.t, (TBar.o + TBar.c) * 0.5), update); + _ohl3.Add((TBar.t, (TBar.o + TBar.h + TBar.l) * 0.333333333333333), update); + _hlc3.Add((TBar.t, (TBar.h + TBar.l + TBar.c) * 0.333333333333333), update); + _ohlc4.Add((TBar.t, (TBar.o + TBar.h + TBar.l + TBar.c) * 0.25), update); + _hlcc4.Add((TBar.t, (TBar.h + TBar.l + TBar.c + TBar.c) * 0.25), update); + + this.OnEvent(update); + return TBar; + } + + public delegate void NewDataEventHandler(object source, TSeriesEventArgs args); + public event NewDataEventHandler Pub; + protected virtual void OnEvent(bool update = false) { if (Pub != null && Pub.Target != this) { + Pub(this, new TSeriesEventArgs { update = update }); } } + + public void Sub(object source, TSeriesEventArgs e) { TBars ss = (TBars)source; if (ss.Count > 1) { + for (int i = 0; i < ss.Count; i++) { this.Add(ss[i]); } + } else { + this.Add(ss[ss.Count - 1], e.update); + } + } +} diff --git a/Calculations/_Updated/TEMA_Series.cs b/Calculations/_Updated/TEMA_Series.cs new file mode 100644 index 00000000..b109995b --- /dev/null +++ b/Calculations/_Updated/TEMA_Series.cs @@ -0,0 +1,123 @@ +namespace QuanTAlib; + +using System; +using System.Linq; + +/* +TEMA: Triple 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/ + +Remark: + ema1 = EMA(close, length) + ema2 = EMA(ema1, length) + ema3 = EMA(ema2, length) + TEMA = 3 * (ema1 - ema2) + ema3 + + */ + +public class TEMA_Series : TSeries { + private double _k; + private double _sum, _oldsum; + private double _lastema1, _oldema1, _lastema2, _oldema2, _lastema3, _oldema3; + private int _len; + private readonly bool _useSMA; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + +//core constructor + public TEMA_Series(int period, bool useNaN, bool useSMA) : base() { + _period = period; + _NaN = useNaN; + _useSMA = useSMA; + Name = $"TEMA({period})"; + _k = 2.0 / (_period + 1); + _len = 0; + _sum = _oldsum = _lastema1 = _lastema2 = _lastema3 = 0; + } + public TEMA_Series() : this(0, false, true) {} + public TEMA_Series(int period) : this(period, false, true) {} + public TEMA_Series(TBars source) : this(source.Close, 0, false) {} + public TEMA_Series(TBars source, int period) : this(source.Close, period, false) {} + public TEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {} + public TEMA_Series(TSeries source, int period) : this(source, period, false, true) {} + public TEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {} + public TEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + +// core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (update) { + _lastema1 = _oldema1; + _lastema2 = _oldema2; + _lastema3 = _oldema3; + _sum = _oldsum; + } + else { + _oldema1 = _lastema1; + _oldema2 = _lastema2; + _oldema3 = _lastema3; + _oldsum = _sum; + _len++; + } + + if (_period == 0) { _k = 2.0 / (_len + 1); } + + double _ema1, _ema2, _ema3, _tema; + if (this.Count == 0) { + _ema1 = _ema2 = _ema3 =_sum = TValue.v; + } + else if (_len <= _period && _useSMA && _period != 0) { + _sum += TValue.v; + _ema1 = _sum / Math.Min(_len, _period); + _ema2 = _ema1; + _ema3 = _ema2; + } + else { + _ema1 = (TValue.v - _lastema1) * _k + _lastema1; + _ema2 = (_ema1 - _lastema2) * _k + _lastema2; + _ema3 = (_ema2 - _lastema3) * _k + _lastema3; + } + + _tema = (3 * (_ema1 - _ema2)) + _ema3; + + _lastema1 = Double.IsNaN(_ema1)?_lastema1:_ema1; + _lastema2 = Double.IsNaN(_ema2)?_lastema2:_ema2; + _lastema3 = Double.IsNaN(_ema3) ? _lastema3 : _ema3; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _tema); + return base.Add(res, update); + } + +//variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _sum = _oldsum = _lastema1 = _lastema2 = 0; + _len = 0; + } +} \ No newline at end of file diff --git a/Calculations/_Updated/TRIMA_Series.cs b/Calculations/_Updated/TRIMA_Series.cs new file mode 100644 index 00000000..70313693 --- /dev/null +++ b/Calculations/_Updated/TRIMA_Series.cs @@ -0,0 +1,87 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +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 : TSeries { + private readonly int _p1a, _p1b; + private SMA_Series sma, trima; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public TRIMA_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"xMA({period})"; + _p1a = (int)Math.Floor((period * 0.5) + 1); + _p1b = (int)Math.Ceiling(0.5 * period); + sma = new(_p1a); + trima = new(_p1b); + + } + public TRIMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public TRIMA_Series() : this(period: 0, useNaN: false) { } + public TRIMA_Series(int period) : this(period: period, useNaN: false) { } + public TRIMA_Series(TBars source) : this(source.Close, 0, false) { } + public TRIMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public TRIMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public TRIMA_Series(TSeries source) : this(source, 0, false) { } + public TRIMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN), update); + } + + var _sma = sma.Add(TValue, update); + var _trima = trima.Add(_sma, update); + + var res = (_trima.t, Count < _period - 1 && _NaN ? double.NaN : _trima.v); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + sma.Reset(); + trima.Reset(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/TRIX_Series.cs b/Calculations/_Updated/TRIX_Series.cs new file mode 100644 index 00000000..243dba19 --- /dev/null +++ b/Calculations/_Updated/TRIX_Series.cs @@ -0,0 +1,119 @@ +namespace QuanTAlib; + +using System; +using System.Linq; + +/* +TRIX: Triple Exponential Average Oscillator + Developed by Jack Hutson in the early 1980s, the triple exponential average (TRIX) + has become a popular technical analysis tool to aid chartists in spotting diversions + and directional cues in stock trading patterns. + +Sources: + https://www.investopedia.com/terms/t/trix.asp + + */ + +public class TRIX_Series : TSeries { + private readonly double _k; + private readonly System.Collections.Generic.List _buffer1 = new(); + private readonly System.Collections.Generic.List _buffer2 = new(); + private readonly System.Collections.Generic.List _buffer3 = new(); + private double _lastema1, _lastema2, _lastema3; + private double _llastema1, _llastema2, _llastema3; + + private readonly bool _useSMA; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + +//core constructors + + public TRIX_Series(int period, bool useNaN, bool useSMA) : base() { + _period = period; + _NaN = useNaN; + _useSMA = useSMA; + Name = $"TRIX({period})"; + _k = 2.0 / (_period + 1); + _lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = 0; + } + public TRIX_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public TRIX_Series() : this(0, false, true) {} + public TRIX_Series(int period) : this(period, false, true) {} + public TRIX_Series(TBars source) : this(source.Close, 0, false) {} + public TRIX_Series(TBars source, int period) : this(source.Close, period, false) {} + public TRIX_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) {} + public TRIX_Series(TSeries source, int period) : this(source, period, false, true) {} + public TRIX_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) {} + + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN), update); + } + if (this.Count == 0) { _lastema1 = _lastema2 = _lastema3 = TValue.v; } + if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; } + else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; } + + double _ema1, _ema2, _ema3; + if ((this.Count < _period) && _useSMA) { + BufferTrim(_buffer1, TValue.v, _period, update); + _ema1 = 0; + for (int i = 0; i < _buffer1.Count; i++) { _ema1 += _buffer1[i]; } + _ema1 /= _buffer1.Count; + + BufferTrim(_buffer2, _ema1, _period, update); + _ema2 = 0; + for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; } + _ema2 /= _buffer2.Count; + + BufferTrim(_buffer3, _ema2, _period, update); + _ema3 = 0; + for (int i = 0; i < _buffer3.Count; i++) { _ema3 += _buffer3[i]; } + _ema3 /= _buffer3.Count; + } + else { + _ema1 = (TValue.v - _lastema1) * _k + _lastema1; + _ema2 = (_ema1 - _lastema2) * _k + _lastema2; + _ema3 = (_ema2 - _lastema3) * _k + _lastema3; + } + double _trix = 100 * (_ema3 - _lastema3) / _lastema3; + _lastema1 = _ema1; + _lastema2 = _ema2; + _lastema3 = _ema3; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _trix); + return base.Add(res, update); + } + +//variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + + } +} \ No newline at end of file diff --git a/Calculations/_Updated/TSeries.cs b/Calculations/_Updated/TSeries.cs new file mode 100644 index 00000000..65c09886 --- /dev/null +++ b/Calculations/_Updated/TSeries.cs @@ -0,0 +1,85 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Data; +using System.Linq; + +/* +TSeries is the cornerstone of all QuanTAlib classes. + TSeries is a single List of tuples (time, value) and contains several operators, casts, overloads + and other helpers that simplify usage of library. + Think of TSeries as an equivalent of Numpy array. + + - includes Length property (to mimic array's method) + - includes publishing and subscribing methods that attach to events + + */ +public class TSeriesEventArgs : EventArgs { + public bool update { get; set; } +} + +public class TSeries : List<(DateTime t, double v)> { + public List t => this.Select(item => item.t).ToList(); + public List v => this.Select(item => item.v).ToList(); + public (DateTime t, double v) Last => this[^1]; + public int Length => Count; + public string Name { get; set; } + + public TSeries() { + this.Name = "data"; + } + + public TSeries(string Name) { + this.Name = Name; + } + + public virtual (DateTime t, double v) Add(double v, bool update = false) { + var Value = (t: Count == 0 ? DateTime.Today : this[^1].t.AddDays(1), v); + return Add(Value, update); + } + + public virtual (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (update) { + this[^1] = TValue; + } + else { + base.Add(TValue); + } + + OnEvent(update); + return TValue; + } + + public virtual (DateTime t, double v) Add(TSeries data) { + foreach (var item in data) { Add(item, false); } + return data.Last; + } + + public void Sub(object source, TSeriesEventArgs e) { + var data = (TSeries) source; + if (data == null) { return; } + foreach (var item in data) { Add(item, update: false); } + } + + public delegate void NewEventHandler(object source, TSeriesEventArgs args); + + public event NewEventHandler Pub; + + protected virtual void OnEvent(bool update = false) + { + Pub?.Invoke(this, new TSeriesEventArgs {update = update}); + } + + /// common helpers + public static void BufferTrim(List buffer, double value, int period, bool update) { + if (!update) { + buffer.Add(value); + if (buffer.Count > period && period > 0) { buffer.RemoveAt(0); } + return; + } + buffer[^1] = value; + } + public virtual void Reset() { + } +} diff --git a/Calculations/_Updated/VAR_Series.cs b/Calculations/_Updated/VAR_Series.cs new file mode 100644 index 00000000..97ad50c3 --- /dev/null +++ b/Calculations/_Updated/VAR_Series.cs @@ -0,0 +1,84 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +VAR: Population Variance + Population variance without Bessel's correction + +Sources: + https://en.wikipedia.org/wiki/Variance + Bessel's correction: https://en.wikipedia.org/wiki/Bessel%27s_correction + +Remark: + VAR (Population Variance) is also known as a biased Sample Variance. For unbiased + sample variance use SVAR instead. + + */ + +public class VAR_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public VAR_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"VAR({period})"; + } + public VAR_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public VAR_Series() : this(period: 0, useNaN: false) { } + public VAR_Series(int period) : this(period: period, useNaN: false) { } + public VAR_Series(TBars source) : this(source.Close, 0, false) { } + public VAR_Series(TBars source, int period) : this(source.Close, period, false) { } + public VAR_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public VAR_Series(TSeries source) : this(source, 0, false) { } + public VAR_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + double _pvar = 0; + for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } + _pvar /= this._buffer.Count; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _pvar); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/WMAPE_Series.cs b/Calculations/_Updated/WMAPE_Series.cs new file mode 100644 index 00000000..b7254958 --- /dev/null +++ b/Calculations/_Updated/WMAPE_Series.cs @@ -0,0 +1,85 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +WMAPE: Weighted Mean Absolute Percentage Error + Measures the size of the error in percentage terms. Improves problems with MAPE + when there are zero or close-to-zero values because there would be a division by zero + or values of MAPE tending to infinity. + +Sources: + https://en.wikipedia.org/wiki/WMAPE + + */ + +public class WMAPE_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public WMAPE_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"WMAPE({period})"; + } + public WMAPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public WMAPE_Series() : this(period: 0, useNaN: false) { } + public WMAPE_Series(int period) : this(period: period, useNaN: false) { } + public WMAPE_Series(TBars source) : this(source.Close, 0, false) { } + public WMAPE_Series(TBars source, int period) : this(source.Close, period, false) { } + public WMAPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public WMAPE_Series(TSeries source) : this(source, 0, false) { } + public WMAPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _sma = _buffer.Average(); + + double _div = 0; + double _wmape = 0; + for (int i = 0; i < _buffer.Count; i++) { + _wmape += Math.Abs(_buffer[i] - _sma); + _div += Math.Abs(_buffer[i]); + } + _wmape = (_div != 0) ? _wmape / _div : double.PositiveInfinity; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _wmape); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/WMA_Series.cs b/Calculations/_Updated/WMA_Series.cs new file mode 100644 index 00000000..f8d8bb39 --- /dev/null +++ b/Calculations/_Updated/WMA_Series.cs @@ -0,0 +1,107 @@ +namespace QuanTAlib; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +/* +WMA: (linearly) Weighted Moving Average + 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 : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + private System.Collections.Generic.List _weights = new(); + protected int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + protected int _len; + public int Len { + get { return _len; } + set { _len = value; } + } + + //core constructors + public WMA_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"WMA({period})"; + _len = 1; + _weights = CalculateWeights(_period); + } + public WMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public WMA_Series() : this(period: 0, useNaN: false) { } + public WMA_Series(int period) : this(period: period, useNaN: false) { } + public WMA_Series(TBars source) : this(source.Close, 0, false) { } + public WMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public WMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public WMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update=false) { + BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update); + if (_period == 0) { + _weights = CalculateWeights(_len); + _len++; + } + double _wma = 0; + double totalWeights = (_buffer.Count * (_buffer.Count + 1)) * 0.5; + object lockObj = new object(); + Parallel.For(0, _buffer.Count, i => + { + double temp = _buffer[i] * this._weights[i]; + lock (lockObj) { _wma += temp; } + }); + _wma /= totalWeights; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _wma); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //calculating weights + private static List CalculateWeights(int period) { + List weights = new List(period); + for (int i = 0; i < period; i++) { + weights.Add(i + 1); + } + return weights; + } + + //reset calculation + public override void Reset() { + _len = 0; + _weights = CalculateWeights(_period); + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/ZLEMA_Series.cs b/Calculations/_Updated/ZLEMA_Series.cs new file mode 100644 index 00000000..81ad2d67 --- /dev/null +++ b/Calculations/_Updated/ZLEMA_Series.cs @@ -0,0 +1,97 @@ +namespace QuanTAlib; + +using System; +using System.Linq; + +/* +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 : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + private int _len; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private readonly EMA_Series _ema; + + //core constructor + public ZLEMA_Series(int period, bool useNaN, bool useSMA) : base() { + _period = period; + _NaN = useNaN; + Name = $"ZLEMA({period})"; + _len = 1; + _ema = new(period); + } + //generic constructors (source) + + public ZLEMA_Series() : this(0, false, true) { } + public ZLEMA_Series(int period) : this(period, false, true) { } + public ZLEMA_Series(TBars source) : this(source.Close, 0, false) { } + public ZLEMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public ZLEMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public ZLEMA_Series(TSeries source, int period) : this(source, period, false, true) { } + public ZLEMA_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { } + public ZLEMA_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) { + BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update); + int _lag; + if (_period == 0) { + _lag = (int)((_len - 1) * 0.5); + _len++; + } + else { _lag = (int)((_period - 1) * 0.5); } + _lag = Math.Min(_lag, _buffer.Count - 1); + _lag = Math.Max(_lag, 0) + 1; + double _zlValue = 2 * TValue.v - _buffer[^_lag]; + double _zlema = _ema.Add((TValue.t, _zlValue), update).v; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zlema); + return base.Add(res, update); + } + + //variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + _ema.Reset(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/ZL_Series.cs b/Calculations/_Updated/ZL_Series.cs new file mode 100644 index 00000000..cfb71d20 --- /dev/null +++ b/Calculations/_Updated/ZL_Series.cs @@ -0,0 +1,93 @@ +namespace QuanTAlib; + +using System; +using System.Linq; + +/* +ZL: Zero Lag + Data is de-lagged by removing the data from “lag” days ago, thus removing + (or attempting to) the cumulative effect of the moving average. + +Calculation: + Lag = (Period-1)/2 + ZL = Data + (Data - Data(Lag days ago) ) + +Sources: + https://mudrex.com/blog/zero-lag-ema-trading-strategy/ + + */ + +public class ZL_Series: TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + private int _len; + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + private readonly EMA_Series _ema; + + //core constructor + public ZL_Series(int period, bool useNaN, bool useSMA) : base() { + _period = period; + _NaN = useNaN; + Name = $"ZL({period})"; + _len = 1; + _ema = new(period); + } + //generic constructors (source) + + public ZL_Series() : this(0, false, true) { } + public ZL_Series(int period) : this(period, false, true) { } + public ZL_Series(TBars source) : this(source.Close, 0, false) { } + public ZL_Series(TBars source, int period) : this(source.Close, period, false) { } + public ZL_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public ZL_Series(TSeries source, int period) : this(source, period, false, true) { } + public ZL_Series(TSeries source, int period, bool useNaN) : this(source, period, useNaN, true) { } + public ZL_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) { + BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update); + int _lag; + if (_period == 0) { + _lag = (int)((_len - 1) * 0.5); + _len++; + } + else { _lag = (int)((_period - 1) * 0.5); } + _lag = Math.Min(_lag, _buffer.Count - 1); + _lag = Math.Max(_lag, 0) + 1; + double _zlValue = 2 * TValue.v - _buffer[^_lag]; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zlValue); + return base.Add(res, update); + } + + //variation of Add() + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + _ema.Reset(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/ZSCORE_Series.cs b/Calculations/_Updated/ZSCORE_Series.cs new file mode 100644 index 00000000..8b213c04 --- /dev/null +++ b/Calculations/_Updated/ZSCORE_Series.cs @@ -0,0 +1,91 @@ +using System.Linq; + +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* +ZSCORE: number of standard deviations from SMA + Z-score describes a value's relationship to the mean of a series, as measured in + terms of standard deviations from the mean. If a Z-score is 0, it indicates that + the data point's score is identical to the mean score. A Z-score of 1.0 would + indicate a value that is one standard deviation from the mean. Z-scores may be + positive or negative, with a positive value indicating the score is above the + mean and a negative score indicating it is below the mean. + +Sources: + https://en.wikipedia.org/wiki/Z-score + https://www.investopedia.com/terms/z/zscore.asp + +Calculation: + std = std * STDEV(close, length) + mean = SMA(close, length) + ZSCORE = (close - mean) / std + + */ + +public class ZSCORE_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public ZSCORE_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"ZSCORE({period})"; + } + public ZSCORE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public ZSCORE_Series() : this(period: 0, useNaN: false) { } + public ZSCORE_Series(int period) : this(period: period, useNaN: false) { } + public ZSCORE_Series(TBars source) : this(source.Close, 0, false) { } + public ZSCORE_Series(TBars source, int period) : this(source.Close, period, false) { } + public ZSCORE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public ZSCORE_Series(TSeries source) : this(source, 0, false) { } + public ZSCORE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + double _sma = _buffer.Average(); + + double _pvar = 0; + for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } + _pvar /= this._buffer.Count; + double _psdev = Math.Sqrt(_pvar); + double _zscore = (_psdev == 0) ? 1 : (TValue.v - _sma) / _psdev; + + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _zscore); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Calculations/_Updated/zMA_Series.cs b/Calculations/_Updated/zMA_Series.cs new file mode 100644 index 00000000..c37a41e5 --- /dev/null +++ b/Calculations/_Updated/zMA_Series.cs @@ -0,0 +1,72 @@ +namespace QuanTAlib; +using System; +using System.Collections.Generic; + +/* + + */ + +public class xMA_Series : TSeries { + private readonly System.Collections.Generic.List _buffer = new(); + + protected readonly int _period; + protected readonly bool _NaN; + protected readonly TSeries _data; + + //core constructors + public xMA_Series(int period, bool useNaN) : base() { + _period = period; + _NaN = useNaN; + Name = $"xMA({period})"; + } + public xMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) { + _data = source; + Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})"; + _data.Pub += Sub; + Add(_data); + } + public xMA_Series() : this(period: 0, useNaN: false) { } + public xMA_Series(int period) : this(period: period, useNaN: false) { } + public xMA_Series(TBars source) : this(source.Close, 0, false) { } + public xMA_Series(TBars source, int period) : this(source.Close, period, false) { } + public xMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { } + public xMA_Series(TSeries source) : this(source, 0, false) { } + public xMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { } + + ////////////////// + // core Add() algo + public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) { + if (double.IsNaN(TValue.v)) { + return base.Add((TValue.t, Double.NaN), update); + } + + BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update); + + double _xma = 0; + var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _xma); + return base.Add(res, update); + } + + public override (DateTime t, double v) Add(TSeries data) { + if (data == null) { return (DateTime.Today, Double.NaN); } + foreach (var item in data) { Add(item, false); } + return _data.Last; + } + public new (DateTime t, double v) Add((DateTime t, double v) TValue) { + return Add(TValue, false); + } + public (DateTime t, double v) Add(bool update) { + return this.Add(TValue: _data.Last, update: update); + } + public (DateTime t, double v) Add() { + return Add(TValue: _data.Last, update: false); + } + private new void Sub(object source, TSeriesEventArgs e) { + Add(TValue: _data.Last, update: e.update); + } + + //reset calculation + public override void Reset() { + _buffer.Clear(); + } +} \ No newline at end of file diff --git a/Indicators/Charts/2MACross_chart.cs b/Indicators/Charts/2MACross_chart.cs index 279dab74..2bc81b8e 100644 --- a/Indicators/Charts/2MACross_chart.cs +++ b/Indicators/Charts/2MACross_chart.cs @@ -7,7 +7,7 @@ namespace QuanTAlib; public class MovingAverage_chart : Indicator { #region Parameters [InputParameter("MA1: Type:", 0, variants: new object[] - { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FMA", 7, "DEMA", 8, "TEMA", 9, + { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9, "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})] private int MA1type = 15; @@ -20,7 +20,7 @@ public class MovingAverage_chart : Indicator { private int MA1DataSource = 3; [InputParameter("MA2: Type:", 3, variants: new object[] - { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FMA", 7, "DEMA", 8, "TEMA", 9, + { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9, "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})] private int MA2type = 16; @@ -97,8 +97,8 @@ public class MovingAverage_chart : Indicator { this.Name += $"DWMA"; break; case 7: - MA1 = new FMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period); - this.Name += $"FMA"; + MA1 = new FWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period); + this.Name += $"FWMA"; break; case 8: MA1 = new DEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false); @@ -171,8 +171,8 @@ public class MovingAverage_chart : Indicator { this.Name += $"DWMA"; break; case 7: - MA2 = new FMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period); - this.Name += $"FMA"; + MA2 = new FWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period); + this.Name += $"FWMA"; break; case 8: MA2 = new DEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false); diff --git a/Indicators/Charts/2MASlope_chart.cs b/Indicators/Charts/2MASlope_chart.cs index 4f65c53e..360af677 100644 --- a/Indicators/Charts/2MASlope_chart.cs +++ b/Indicators/Charts/2MASlope_chart.cs @@ -7,7 +7,7 @@ namespace QuanTAlib; public class MovingAverageSlope_chart : Indicator { #region Parameters [InputParameter("MA1: Type:", 0, variants: new object[] - { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FMA", 7, "DEMA", 8, "TEMA", 9, + { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9, "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})] private int MA1type = 16; @@ -20,7 +20,7 @@ public class MovingAverageSlope_chart : Indicator { private int MA1DataSource = 3; [InputParameter("MA2: Type:", 3, variants: new object[] - { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FMA", 7, "DEMA", 8, "TEMA", 9, + { "SMA", 0, "EMA", 1, "WMA", 2, "T3", 3, "SMMA", 4, "TRIMA", 5, "DWMA", 6, "FWMA", 7, "DEMA", 8, "TEMA", 9, "ALMA", 10, "HMA", 11, "HEMA", 12, "MAMA", 13, "KAMA", 14, "ZLEMA", 15, "JMA", 16})] private int MA2type = 6; @@ -101,8 +101,8 @@ public class MovingAverageSlope_chart : Indicator { this.Name += $"DWMA"; break; case 7: - MA1 = new FMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period); - this.Name += $"FMA"; + MA1 = new FWMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period); + this.Name += $"FWMA"; break; case 8: MA1 = new DEMA_Series(source: bars.Select(this.MA1DataSource), period: this.MA1Period, useNaN: false); @@ -175,8 +175,8 @@ public class MovingAverageSlope_chart : Indicator { this.Name += $"DWMA"; break; case 7: - MA2 = new FMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period); - this.Name += $"FMA"; + MA2 = new FWMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period); + this.Name += $"FWMA"; break; case 8: MA2 = new DEMA_Series(source: bars.Select(this.MA2DataSource), period: this.MA2Period, useNaN: false); @@ -227,11 +227,7 @@ public class MovingAverageSlope_chart : Indicator { 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); + this.bars.Add(this.Time(),this.Open(), this.High(), this.Low(), this.Close(), this.Volume(), update); this.SetValue(this.MA1[^1].v, lineIndex: 0); this.SetValue(this.MA2[^1].v, lineIndex: 1); diff --git a/Indicators/Charts/JMA_chart.cs b/Indicators/Charts/JMA_chart.cs index 366d759b..9390ea59 100644 --- a/Indicators/Charts/JMA_chart.cs +++ b/Indicators/Charts/JMA_chart.cs @@ -64,9 +64,7 @@ public class JMA_chart : Indicator { rec[PriceType.Close], rec[PriceType.Volume]); } - indicator = new(source: bars.Select(DataSource), period: Period, - phase: Jphase, vshort: Vshort, vlong: Vlong, - useNaN: true); + indicator = new(source: bars.Select(DataSource), period: Period, phase: Jphase, vshort: Vshort, vlong: Vlong, useNaN: true); } protected override void OnUpdate(UpdateArgs args) { diff --git a/Indicators/Indicators.csproj b/Indicators/Indicators.csproj index 8c28acf6..0446cc33 100644 --- a/Indicators/Indicators.csproj +++ b/Indicators/Indicators.csproj @@ -17,6 +17,8 @@ 0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d 0.2.1-dev.2 NETSDK1057 + true + NETSDK1057 True diff --git a/Strategies/SimpleMACross1.cs b/Strategies/SimpleMACross1.cs index 117af5ca..f6ffaeb6 100644 --- a/Strategies/SimpleMACross1.cs +++ b/Strategies/SimpleMACross1.cs @@ -64,7 +64,7 @@ namespace SimpleMACross { bars.Add(hdm.Last().TimeLeft, hdm.Last()[PriceType.Open], hdm.Last()[PriceType.High], hdm.Last()[PriceType.Low], hdm.Last()[PriceType.Close], hdm.Last()[PriceType.Volume], update); - if (!update) {this.LogInfo($"{bars.Close.Last().t} OHLC4:{(double)bars.OHLC4}");} + if (!update) {this.LogInfo($"{bars.Close.Last().t} OHLC4:{(double)bars.OHLC4.Last.v}");} } diff --git a/Strategies/Strategies.csproj b/Strategies/Strategies.csproj index aa04c0c4..08f3bcdf 100644 --- a/Strategies/Strategies.csproj +++ b/Strategies/Strategies.csproj @@ -17,6 +17,8 @@ 0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d 0.2.1-dev.2 NETSDK1057 + true + NETSDK1057 True diff --git a/Tests/Basic tests/Indicators.cs b/Tests/Basic tests/Indicators.cs new file mode 100644 index 00000000..29476d01 --- /dev/null +++ b/Tests/Basic tests/Indicators.cs @@ -0,0 +1,153 @@ +using Xunit; +using System; +using QuanTAlib; + +namespace Basics; +#nullable disable +public class Indicators +{ + private static Type[] maSeriesTypes = new Type[] + { + typeof(SMA_Series), + typeof(EMA_Series), + typeof(DEMA_Series), + typeof(TEMA_Series), + typeof(WMA_Series), + typeof(ALMA_Series), + typeof(DWMA_Series), + typeof(FWMA_Series), + typeof(HMA_Series), + typeof(ZLEMA_Series), + typeof(RMA_Series), + typeof(HEMA_Series), + typeof(JMA_Series), + typeof(CUSUM_Series), + typeof(SMMA_Series), + typeof(T3_Series), + typeof(KAMA_Series), + typeof(TRIMA_Series), +}; + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Name_exists(Type classType) + { + TSeries data = new("Data") {1,2,3}; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + Assert.NotEmpty(MA_Series.Name); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Series_Length(Type classType) + { + GBM_Feed feed = new(1000); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + Assert.Equal(1000, MA_Series.Count); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Return_data(Type classType) + { + TSeries data = new() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + var result = MA_Series.Add(20); + Assert.Equal(result.v, MA_Series.Last.v); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Update(Type classType) + { + TSeries data = new() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + var pre_update = MA_Series.Last.v; + + double pre_data = data.Last.v; + data.Add(20, true); + data.Add(pre_data, true); + + Assert.Equal(pre_update, MA_Series.Last.v); + Assert.Equal(data.Count, MA_Series.Count); +} + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Period_zero(Type classType) + { + GBM_Feed feed = new(100); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 0, false) as TSeries; + Assert.Equal(data.Count, MA_Series.Count); + Assert.False(double.IsNaN(MA_Series.Last.v)); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Reset(Type classType) + { + GBM_Feed feed = new(10); + TSeries data = feed.OHLC4; + var MA_Series = Activator.CreateInstance(classType, data, 10, false) as TSeries; + MA_Series.Reset(); + data.Add(0); + Assert.Equal(data.Last.v, MA_Series.Last.v); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Period_one(Type classType) + { + GBM_Feed feed = new(100); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 1, false) as TSeries; + Assert.InRange(MA_Series.Last.v - data.Last.v, -10e-6, 10e-6); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void NaN_test(Type classType) + { + GBM_Feed feed = new(100); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries; + Assert.True(double.IsNaN(MA_Series[0].v)); + Assert.True(double.IsNaN(MA_Series[8].v)); + Assert.False(double.IsNaN(MA_Series[9].v)); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Edge_numbers(Type classType) + { + TSeries data = new() { double.Epsilon, double.PositiveInfinity, double.MaxValue, double.NegativeInfinity }; + var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries; + Assert.Equal(4, MA_Series.Count); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void handling_NaN(Type classType) { + TSeries data = new("Name") { 1, 2, 3, 4, 5, 6, double.NaN, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; +var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries; + Assert.False(double.IsNaN(MA_Series.Last.v)); + } + +public static IEnumerable MASeriesData() + { + foreach (var type in maSeriesTypes) + { + yield return new object[] { type }; + } + } +} +#nullable restore \ No newline at end of file diff --git a/Tests/Basic tests/Oscillators.cs b/Tests/Basic tests/Oscillators.cs new file mode 100644 index 00000000..458386fb --- /dev/null +++ b/Tests/Basic tests/Oscillators.cs @@ -0,0 +1,158 @@ +using Xunit; +using System; +using System.Runtime.InteropServices; +using QuanTAlib; + +namespace Basics; +#nullable disable +public class Oscillators +{ + private static Type[] maSeriesTypes = new Type[] + { + typeof(BIAS_Series), + typeof(MAX_Series), + typeof(MIN_Series), + typeof(MIDPOINT_Series), + typeof(ZL_Series), + typeof(DECAY_Series), + typeof(ENTROPY_Series), + typeof(KURTOSIS_Series), + typeof(MAD_Series), + typeof(MAPE_Series), + typeof(MSE_Series), + typeof(SDEV_Series), + typeof(SMAPE_Series), + typeof(WMAPE_Series), + typeof(SSDEV_Series), + typeof(VAR_Series), + typeof(SVAR_Series), + typeof(MEDIAN_Series), + typeof(ZSCORE_Series), + typeof(CMO_Series), + typeof(RSI_Series), + typeof(TRIX_Series), +}; + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Name_exists(Type classType) + { + TSeries data = new("Data") {1,2,3}; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + Assert.NotEmpty(MA_Series.Name); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Series_Length(Type classType) + { + GBM_Feed feed = new(1000); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + Assert.Equal(1000, MA_Series.Count); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Return_data(Type classType) + { + TSeries data = new() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + var result = MA_Series.Add(20); + Assert.Equal(result.v, MA_Series.Last.v); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Update(Type classType) + { + TSeries data = new() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + var MA_Series = Activator.CreateInstance(classType, data, 5, false) as TSeries; + var pre_update = MA_Series.Last.v; + + double pre_data = data.Last.v; + data.Add(20, true); + data.Add(pre_data, true); + + Assert.Equal(pre_update, MA_Series.Last.v); + Assert.Equal(data.Count, MA_Series.Count); +} + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Period_zero(Type classType) + { + GBM_Feed feed = new(100); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 0, false) as TSeries; + Assert.Equal(data.Count, MA_Series.Count); + Assert.False(double.IsNaN(MA_Series.Last.v)); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Reset(Type classType) + { + GBM_Feed feed = new(10); + TSeries data = feed.OHLC4; + var MA_Series = Activator.CreateInstance(classType, data, 10, false) as TSeries; + MA_Series.Reset(); + data.Add(1); + Assert.False(double.IsNaN(MA_Series.Last.v)); +} + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Period_one(Type classType) + { + GBM_Feed feed = new(100); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 1, false) as TSeries; + Assert.False(double.IsNaN(MA_Series[^1].v)); +} + + [Theory] + [MemberData(nameof(MASeriesData))] + public void NaN_test(Type classType) + { + GBM_Feed feed = new(100); + TSeries data = feed.OHLC4; + + var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries; + Assert.True(double.IsNaN(MA_Series[0].v)); + Assert.True(double.IsNaN(MA_Series[8].v)); + Assert.False(double.IsNaN(MA_Series[9].v)); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void Edge_numbers(Type classType) + { + TSeries data = new() { double.Epsilon, double.PositiveInfinity, double.MaxValue, double.NegativeInfinity }; + var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries; + Assert.Equal(4, MA_Series.Count); + } + + [Theory] + [MemberData(nameof(MASeriesData))] + public void handling_NaN(Type classType) { + TSeries data = new("Name") { 1, 2, 3, 4, 5, 6, double.NaN, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; +var MA_Series = Activator.CreateInstance(classType, data, 10, true) as TSeries; + Assert.False(double.IsNaN(MA_Series.Last.v)); + } + +public static IEnumerable MASeriesData() + { + foreach (var type in maSeriesTypes) + { + yield return new object[] { type }; + } + } +} +#nullable restore \ No newline at end of file diff --git a/Tests/Basics/Abstract_Test.cs b/Tests/Basics/Abstract_Test.cs deleted file mode 100644 index b2ffb9a3..00000000 --- a/Tests/Basics/Abstract_Test.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Basics; -public class Abstract_Test -{ - [Fact] - public void Single_Add_variations() - { - TSeries s = new() { 1,2,3,4,5 }; - SMA_Series a = new(s, 3) - { - { (DateTime.Today, 10), true } - }; - Assert.Equal(s.Length, a.Length); - a.Add(true); - Assert.Equal(s.Length, a.Length); - a.Add(); - Assert.Equal(s.Length+1, a.Length); - } - -} diff --git a/Tests/Basics/TSeries_Test.cs b/Tests/Basics/TSeries_Test.cs deleted file mode 100644 index 2344e85c..00000000 --- a/Tests/Basics/TSeries_Test.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Basics; -public class TSeries_Test -{ - [Fact] - public void InsertingTuple() - { - TSeries s = new() { (t: DateTime.Today, v: double.Epsilon) }; - Assert.Equal((DateTime.Today, double.Epsilon), s[^1]); - } - - [Fact] - public void CastingTwoParameters() - { - TSeries s = new() - { - { DateTime.Today, 0.0 } - }; - Assert.Equal(0.0, s[s.Count - 1].v); - Assert.Equal(DateTime.Today, s[s.Count - 1].t); - } - - [Fact] - public void CastingOneParameter() - { - TSeries s = new() - { - double.PositiveInfinity - }; - Assert.Equal(double.PositiveInfinity, (double)s); - } - - [Fact] - public void UpdatingValue() - { - TSeries s = new() { 1, 2, 3, 4, 5 }; - s.Add(0.0, update: true); - Assert.Equal(0.0, (double)s); - Assert.Equal(5, s.Count); - } - [Fact] - public void ReflectingSeries() - { - TSeries s = new() { 1, 2, 3, 4, 5 }; - TSeries t = s; - Assert.Equal(5, (double)t); - Assert.Equal(5, t.Count); - } - [Fact] - public void BroadcastingEvents() - { - TSeries s = new() { 1, 2, 3, 4, 5 }; - TSeries t = new(); - 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 deleted file mode 100644 index b35e0d4b..00000000 --- a/Tests/MovingAvg/ALMA_Test.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class Update -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { Double.NaN, 0, 1, 2, 3, 4 }; - ALMA_Series c = new(a, 4); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(10, update: true); - Assert.Equal(a.Count, c.Count); - Assert.Equal(0, a[1].v); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - ALMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 842caacf..00000000 --- a/Tests/MovingAvg/BBANDS_Test.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class BBANDS_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - BBANDS_Series c = new(a, 4,2.5); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - Assert.Equal(a.Count, c.Mid.Count); - Assert.Equal(a.Count, c.Upper.Count); - Assert.Equal(a.Count, c.Lower.Count); - Assert.Equal(a.Count, c.PercentB.Count); - Assert.Equal(a.Count, c.Zscore.Count); - Assert.Equal(a.Count, c.Bandwidth.Count); - - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - Assert.Equal(a.Count, c.Mid.Count); - Assert.Equal(a.Count, c.Upper.Count); - Assert.Equal(a.Count, c.Lower.Count); - Assert.Equal(a.Count, c.PercentB.Count); - Assert.Equal(a.Count, c.Zscore.Count); - Assert.Equal(a.Count, c.Bandwidth.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - BBANDS_Series c = new(a, 4, 2.5); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - Assert.Equal(a.Count, c.Mid.Count); - Assert.Equal(a.Count, c.Upper.Count); - Assert.Equal(a.Count, c.Lower.Count); - Assert.Equal(a.Count, c.PercentB.Count); - Assert.Equal(a.Count, c.Zscore.Count); - Assert.Equal(a.Count, c.Bandwidth.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - Assert.Equal(a.Count, c.Mid.Count); - Assert.Equal(a.Count, c.Upper.Count); - Assert.Equal(a.Count, c.Lower.Count); - 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 deleted file mode 100644 index 7ce76446..00000000 --- a/Tests/MovingAvg/DEMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class DEMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - DEMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - DEMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} diff --git a/Tests/MovingAvg/DWMA_Test.cs b/Tests/MovingAvg/DWMA_Test.cs deleted file mode 100644 index 471f1713..00000000 --- a/Tests/MovingAvg/DWMA_Test.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class DWMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { Double.NaN, 0, 1, 2, 3, 4 }; - DWMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - Assert.Equal(0, a[1].v); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - DWMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index fddc3279..00000000 --- a/Tests/MovingAvg/EMA_Test.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class EMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { Double.NaN, 0, 1, 2, 3, 4 }; - EMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - Assert.Equal(0, a[1].v); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - EMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} diff --git a/Tests/MovingAvg/FMA_Test.cs b/Tests/MovingAvg/FMA_Test.cs deleted file mode 100644 index 2369784d..00000000 --- a/Tests/MovingAvg/FMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class FMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - FMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - FMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index eaed9490..00000000 --- a/Tests/MovingAvg/HEMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class HEMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - HEMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - HEMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index e2cd00dc..00000000 --- a/Tests/MovingAvg/HMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class HMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - HMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - HMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 2623d325..00000000 --- a/Tests/MovingAvg/JMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class JMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - JMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - JMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 87714240..00000000 --- a/Tests/MovingAvg/KAMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class KAMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - KAMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - KAMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index dd0ee4ad..00000000 --- a/Tests/MovingAvg/MACD_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class MACD_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MACD_Series c = new(a, 26,12,9); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MACD_Series c = new(a, 26,12,9); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 6bdea4ff..00000000 --- a/Tests/MovingAvg/RMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class RMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - RMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - RMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 016c0391..00000000 --- a/Tests/MovingAvg/RSI_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class RSI_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - RSI_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - RSI_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index b08b268f..00000000 --- a/Tests/MovingAvg/SMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class SMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 418fe695..00000000 --- a/Tests/MovingAvg/SMMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class SMMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SMMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SMMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index af7b0df9..00000000 --- a/Tests/MovingAvg/TEMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class TEMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - TEMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - TEMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 52e12045..00000000 --- a/Tests/MovingAvg/WMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class WMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - WMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - WMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index dad74ec0..00000000 --- a/Tests/MovingAvg/ZLEMA_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace MovingAvg; -public class ZLEMA_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - ZLEMA_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - ZLEMA_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} diff --git a/Tests/Basics/ADD_Test.cs b/Tests/Pairs/ADD_Test.cs similarity index 98% rename from Tests/Basics/ADD_Test.cs rename to Tests/Pairs/ADD_Test.cs index 66e2f122..2c86e5a8 100644 --- a/Tests/Basics/ADD_Test.cs +++ b/Tests/Pairs/ADD_Test.cs @@ -2,7 +2,7 @@ using Xunit; using System; using QuanTAlib; -namespace Basics; +namespace Pairs; public class ADD_Test { [Fact] diff --git a/Tests/Basics/DIV_Test.cs b/Tests/Pairs/DIV_Test.cs similarity index 98% rename from Tests/Basics/DIV_Test.cs rename to Tests/Pairs/DIV_Test.cs index 0421bff8..a8286017 100644 --- a/Tests/Basics/DIV_Test.cs +++ b/Tests/Pairs/DIV_Test.cs @@ -2,7 +2,7 @@ using Xunit; using System; using QuanTAlib; -namespace Basics; +namespace Pairs; public class DIV_Test { [Fact] diff --git a/Tests/Basics/MUL_Test.cs b/Tests/Pairs/MUL_Test.cs similarity index 98% rename from Tests/Basics/MUL_Test.cs rename to Tests/Pairs/MUL_Test.cs index 30d1d536..90ad3888 100644 --- a/Tests/Basics/MUL_Test.cs +++ b/Tests/Pairs/MUL_Test.cs @@ -2,7 +2,7 @@ using Xunit; using System; using QuanTAlib; -namespace Basics; +namespace Pairs; public class MUL_Test { [Fact] diff --git a/Tests/Basics/SUB_Test.cs b/Tests/Pairs/SUB_Test.cs similarity index 98% rename from Tests/Basics/SUB_Test.cs rename to Tests/Pairs/SUB_Test.cs index b9f18584..04775464 100644 --- a/Tests/Basics/SUB_Test.cs +++ b/Tests/Pairs/SUB_Test.cs @@ -2,7 +2,7 @@ using Xunit; using System; using QuanTAlib; -namespace Basics; +namespace Pairs; public class SUB_Test { [Fact] diff --git a/Tests/Basics/TBars_Test.cs b/Tests/Pairs/TBars_Test.cs similarity index 95% rename from Tests/Basics/TBars_Test.cs rename to Tests/Pairs/TBars_Test.cs index bc49e764..531703bc 100644 --- a/Tests/Basics/TBars_Test.cs +++ b/Tests/Pairs/TBars_Test.cs @@ -1,112 +1,112 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Basics; -public class TBars_Test -{ - [Fact] - public void InsertingTuple() - { - TBars s = new() { (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue, c: Double.NegativeInfinity, v: Double.PositiveInfinity) }; - var tup = (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue, - c: Double.NegativeInfinity, v: Double.PositiveInfinity); - Assert.Equal(tup, s[^1]); - } - - [Fact] - public void Casting_Parameters() - { - TBars s = new() - { - { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false } - }; - Assert.Equal(0.1, s[^1].o); - Assert.Equal(1.1, s[^1].h); - Assert.Equal(2.1, s[^1].l); - Assert.Equal(3.1, s[^1].c); - Assert.Equal(4.1, s[^1].v); - Assert.Equal(DateTime.Today, s[^1].t); - Assert.Single(s); - } - - [Fact] - public void Updating_Value() - { - TBars s = new() - { - { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 } - }; - s.Add(DateTime.Today, 1.0, 1.0, 1.0, 1.0, 1.0, update: false); - s.Add(DateTime.Today, 0.0, 0.0, 0.0, 0.0, 0.0, update: true); - Assert.Equal(0.0, s[^1].o); - Assert.Equal(0.0, s[^1].h); - Assert.Equal(0.0, s[^1].l); - Assert.Equal(0.0, s[^1].c); - Assert.Equal(0.0, s[^1].v); - Assert.Equal(2, s.Count); - } - [Fact] - public void Extracting_TSeries() - { - TBars s = new() - { - { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 }, - { DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1 } - }; - - TSeries t = s.Open; - Assert.Equal(t.t, s.Open.t); - Assert.Equal(t.v, s.Open.v); - - t = s.High; - Assert.Equal(t.t, s.High.t); - Assert.Equal(t.v, s.High.v); - - t = s.Low; - Assert.Equal(t.t, s.Low.t); - Assert.Equal(t.v, s.Low.v); - - t = s.Close; - Assert.Equal(t.t, s.Close.t); - Assert.Equal(t.v, s.Close.v); - - t = s.Volume; - Assert.Equal(t.t, s.Volume.t); - Assert.Equal(t.v, s.Volume.v); - - t = s.HL2; - Assert.Equal(t.t, s.HL2.t); - Assert.Equal(t.v, s.HL2.v); - - t = s.OC2; - Assert.Equal(t.t, s.OC2.t); - Assert.Equal(t.v, s.OC2.v); - - t = s.OHL3; - Assert.Equal(t.t, s.OHL3.t); - Assert.Equal(t.v, s.OHL3.v); - - t = s.HLC3; - Assert.Equal(t.t, s.HLC3.t); - Assert.Equal(t.v, s.HLC3.v); - - t = s.OHLC4; - Assert.Equal(t.t, s.OHLC4.t); - Assert.Equal(t.v, s.OHLC4.v); - - t = s.HLCC4; - Assert.Equal(t.t, s.HLCC4.t); - Assert.Equal(t.v, s.HLCC4.v); - } - [Fact] - public void Broadcasting_Events() - { - TBars s = new() { (DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1) }; - TSeries t = new(); - s.Close.Pub += t.Sub; - 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); - } -} +using Xunit; +using System; +using QuanTAlib; + +namespace Bars; +public class TBars_Test +{ + [Fact] + public void InsertingTuple() + { + TBars s = new() { (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue, c: Double.NegativeInfinity, v: Double.PositiveInfinity) }; + var tup = (t: DateTime.Today, o: double.Epsilon, h: double.NaN, l: Double.MaxValue, + c: Double.NegativeInfinity, v: Double.PositiveInfinity); + Assert.Equal(tup, s[^1]); + } + + [Fact] + public void Casting_Parameters() + { + TBars s = new() + { + { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false } + }; + Assert.Equal(0.1, s[^1].o); + Assert.Equal(1.1, s[^1].h); + Assert.Equal(2.1, s[^1].l); + Assert.Equal(3.1, s[^1].c); + Assert.Equal(4.1, s[^1].v); + Assert.Equal(DateTime.Today, s[^1].t); + Assert.Single(s); + } + + [Fact] + public void Updating_Value() + { + TBars s = new() + { + { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 } + }; + s.Add(DateTime.Today, 1.0, 1.0, 1.0, 1.0, 1.0, update: false); + s.Add(DateTime.Today, 0.0, 0.0, 0.0, 0.0, 0.0, update: true); + Assert.Equal(0.0, s[^1].o); + Assert.Equal(0.0, s[^1].h); + Assert.Equal(0.0, s[^1].l); + Assert.Equal(0.0, s[^1].c); + Assert.Equal(0.0, s[^1].v); + Assert.Equal(2, s.Count); + } + [Fact] + public void Extracting_TSeries() + { + TBars s = new() + { + { DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1 }, + { DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1 } + }; + + TSeries t = s.Open; + Assert.Equal(t.t, s.Open.t); + Assert.Equal(t.v, s.Open.v); + + t = s.High; + Assert.Equal(t.t, s.High.t); + Assert.Equal(t.v, s.High.v); + + t = s.Low; + Assert.Equal(t.t, s.Low.t); + Assert.Equal(t.v, s.Low.v); + + t = s.Close; + Assert.Equal(t.t, s.Close.t); + Assert.Equal(t.v, s.Close.v); + + t = s.Volume; + Assert.Equal(t.t, s.Volume.t); + Assert.Equal(t.v, s.Volume.v); + + t = s.HL2; + Assert.Equal(t.t, s.HL2.t); + Assert.Equal(t.v, s.HL2.v); + + t = s.OC2; + Assert.Equal(t.t, s.OC2.t); + Assert.Equal(t.v, s.OC2.v); + + t = s.OHL3; + Assert.Equal(t.t, s.OHL3.t); + Assert.Equal(t.v, s.OHL3.v); + + t = s.HLC3; + Assert.Equal(t.t, s.HLC3.t); + Assert.Equal(t.v, s.HLC3.v); + + t = s.OHLC4; + Assert.Equal(t.t, s.OHLC4.t); + Assert.Equal(t.v, s.OHLC4.v); + + t = s.HLCC4; + Assert.Equal(t.t, s.HLCC4.t); + Assert.Equal(t.v, s.HLCC4.v); + } + [Fact] + public void Broadcasting_Events() + { + TBars s = new() { (DateTime.Today, 2.1, 3.1, 4.1, 5.1, 6.1) }; + TSeries t = new(); + s.Close.Pub += t.Sub; + 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/Series/Update.cs b/Tests/Series/Update.cs deleted file mode 100644 index 91fa9439..00000000 --- a/Tests/Series/Update.cs +++ /dev/null @@ -1,545 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; -using Skender.Stock.Indicators; - -namespace Series; -public class Update { - private readonly GBM_Feed bars; - private readonly Random rnd = new(); - private readonly int period; - - public Update() { - bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0); - period = rnd.Next(28) + 3; - } - - [Fact] public void ADL() { - ADL_Series QL = new(bars); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void ADOSC() { - ADOSC_Series QL = new(bars); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void ALMA() { - ALMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void ATR() { - ATR_Series QL = new(bars, period: period); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void ATRP() { - ATRP_Series QL = new(bars, period: period); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void BBANDS() { - BBANDS_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void BIAS() { - BIAS_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void CCI() { - CCI_Series QL = new(bars, period: period); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void CORR() { - CORR_Series QL = new(d1: bars.High, d2: bars.Low, period: period); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), (DateTime.Today, 0), update: true); - QL.Add((lastData.t, lastData.h), (lastData.t, lastData.l), update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void COVAR() { - COVAR_Series QL = new(d1: bars.High, d2: bars.Low, period); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), (DateTime.Today, 0), update: true); - QL.Add((lastData.t, lastData.h), (lastData.t, lastData.l), update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] - public void DECAY() { - DECAY_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void DEMA() { - DEMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] - public void DWMA() { - DWMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void ENTROPY() { - ENTROPY_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void EMA() { - EMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] - public void FMA() { - FMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void HEMA() { - HEMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void HMA() { - HMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] - public void HWMA() { - HWMA_Series QL = new(source: bars.Close); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void JMA() { - JMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void KAMA() { - KAMA_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void KURTOSIS() { - KURTOSIS_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void LINREG() { - LINREG_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MACD() { - MACD_Series QL = new(source: bars.Close); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - var lastC1 = QL.Signal.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - Assert.Equal(lastC1, QL.Signal.Last()); // same data - } - [Fact] public void MAD() { - MAD_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MAMA() { - MAMA_Series QL = new(source: bars.Close); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - var lastC1 = QL.Fama.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - Assert.Equal(lastC1, QL.Fama.Last()); // same data - } - [Fact] public void MAPE() { - MAPE_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MAX() { - MAX_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MEDIAN() { - MEDIAN_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MIDPOINT() { - MIDPOINT_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MIDPRICE() { - MIDPRICE_Series QL = new(bars, period: period); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MIN() { - MAX_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void MSE() { - MSE_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void OBV() { - OBV_Series QL = new(bars, period: period); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void RSI() { - RSI_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void RMA() { - RMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void SDEV() { - SDEV_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void SMA() { - SMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void SMAPE() { - SMAPE_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void SMMA() { - SMMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void SSDEV() { - SSDEV_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void SUM() { - SUM_Series QL = new(source: bars.Close, period: period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void SVAR() { - SVAR_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void T3() { - SMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void TEMA() { - TEMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void TR() { - TR_Series QL = new(bars); - var lastData = bars.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0, 0, 0, 0, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void TRIMA() { - TRIMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void VAR() { - VAR_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void WMA() { - WMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void WMAPE() { - WMAPE_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void ZLEMA() { - ZLEMA_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } - [Fact] public void ZSCORE() { - ZSCORE_Series QL = new(source: bars.Close, period); - var lastData = bars.Close.Last(); - var lastCalc = QL.Last(); - int lastLen = QL.Count; - QL.Add((DateTime.Today, 0), update: true); - QL.Add(lastData, update: true); - Assert.Equal(lastLen, QL.Count); // same size - Assert.Equal(lastCalc, QL.Last()); // same data - } -} diff --git a/Tests/Statistics/BIAS_Test.cs b/Tests/Statistics/BIAS_Test.cs deleted file mode 100644 index 2b46429c..00000000 --- a/Tests/Statistics/BIAS_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class BIAS_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - BIAS_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - BIAS_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index f7e8aa10..00000000 --- a/Tests/Statistics/ENTP_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class KURTOSIS_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - KURTOSIS_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - KURTOSIS_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index c594ff4b..00000000 --- a/Tests/Statistics/KURT_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class ENTP_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - ENTROPY_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - ENTROPY_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 19cbf086..00000000 --- a/Tests/Statistics/LINREG_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class LINREG_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - LINREG_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - LINREG_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index fcc11764..00000000 --- a/Tests/Statistics/MAD_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MAD_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MAD_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MAD_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 1052f136..00000000 --- a/Tests/Statistics/MAPE_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MAPE_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MAPE_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MAPE_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 785af747..00000000 --- a/Tests/Statistics/MAX_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MAX_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MAX_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MAX_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index ccfc2bcc..00000000 --- a/Tests/Statistics/MED_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MED_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MEDIAN_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MEDIAN_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 917879d8..00000000 --- a/Tests/Statistics/MIN_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MIN_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MIN_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MIN_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 4c8374b7..00000000 --- a/Tests/Statistics/MSE_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class MSE_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - MSE_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - MSE_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index fa871ddb..00000000 --- a/Tests/Statistics/PSDEV_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class PSDEV_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SDEV_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SDEV_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index ef3880b4..00000000 --- a/Tests/Statistics/PVAR_Test .cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class PVAR_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SVAR_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SVAR_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index e8b76a5d..00000000 --- a/Tests/Statistics/SDEV_Test .cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class SDEV_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SSDEV_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SSDEV_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index fcc01a44..00000000 --- a/Tests/Statistics/SMAPE_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class SMAPE_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SMAPE_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SMAPE_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 329cd1f5..00000000 --- a/Tests/Statistics/VAR_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class VAR_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - SVAR_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - SVAR_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - 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 deleted file mode 100644 index 54acfbe5..00000000 --- a/Tests/Statistics/WMAPE_Test.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Xunit; -using System; -using QuanTAlib; - -namespace Statistics; -public class WMAPE_Test -{ - [Fact] - public void Add_Test() - { - TSeries a = new() { 0, 1, 2, 3, 4, 5 }; - WMAPE_Series c = new(a, 3); - Assert.Equal(6, c.Count); - a.Add(5); - Assert.Equal(a.Count, c.Count); - a.Add(0, update: true); - Assert.Equal(a.Count, c.Count); - } - - [Fact] - public void Edge_Test() - { - TSeries a = new() { double.NaN, double.Epsilon, double.PositiveInfinity, double.MaxValue }; - WMAPE_Series c = new(a, 3); - Assert.Equal(a.Count, c.Count); - a.Add(double.NaN); - Assert.Equal(a.Count, c.Count); - a.Add(double.PositiveInfinity); - Assert.Equal(a.Count, c.Count); - } -} diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index fb878d36..07aed4a3 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -1,6 +1,6 @@  - net6.0 + net8.0 preview enable enable @@ -10,6 +10,8 @@ 0.2.1.0 0.2.1-dev.2+Branch.dev.Sha.cb5fe2dc86a78fe9358da810d17952c82299ed3d 0.2.1-dev.2 + $(NoWarn);NETSDK1057 + true @@ -38,4 +40,7 @@ + + + \ No newline at end of file diff --git a/Tests/Validations/Trends/TA_LIB.cs b/Tests/Validations/Trends/TA_LIB.cs index 1d211ba6..11282618 100644 --- a/Tests/Validations/Trends/TA_LIB.cs +++ b/Tests/Validations/Trends/TA_LIB.cs @@ -388,7 +388,7 @@ public class Ta_Lib [Fact] public void SUM() { - SUM_Series QL = new(bars.Close, period, false); + CUSUM_Series QL = new(bars.Close, period, false); Core.Sum(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); for (int i = QL.Length - 1; i > skip; i--) { diff --git a/Tests/Validations/Trends/Tulip.cs b/Tests/Validations/Trends/Tulip.cs index a205b635..959b16d4 100644 --- a/Tests/Validations/Trends/Tulip.cs +++ b/Tests/Validations/Trends/Tulip.cs @@ -426,7 +426,7 @@ public class Tulip_Test public void SUM() { double[][] arrin = { inclose }; double[][] arrout = { outdata }; - SUM_Series QL = new(bars.Close, period, false); + CUSUM_Series QL = new(bars.Close, period, false); Tulip.Indicators.sum.Run(inputs: arrin, options: new double[] { period }, outputs: arrout); for (int i = QL.Length - 1; i > skip; i--) { double QL_item = QL[i].v;