TR and ATR

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