Update RSI_Series to check for period != 0 before calculating RSI

This commit is contained in:
Miha Kralj
2023-04-27 22:30:13 -07:00
parent 3b71ac70c8
commit e1680e9d04
145 changed files with 4826 additions and 4207 deletions
-63
View File
@@ -1,63 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
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)
</summary> */
public class ALMA_Series : Single_TSeries_Indicator
{
private readonly System.Collections.Generic.List<double> _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);
}
}
+49
View File
@@ -0,0 +1,49 @@
namespace QuanTAlib;
using System;
using System.Linq;
using static System.Net.Mime.MediaTypeNames;
/* <summary>
CCI: Commodity Channel Index
Commodity Channel Index is a momentum oscillator used to primarily identify overbought
and oversold levels relative to a mean. CCI measures the current price level relative
to an average price level over a given period of time:
- CCI is relatively high when prices are far above their average.
- CCI is relatively low when prices are far below their average.
Using this method, CCI can be used to identify overbought and oversold levels.
Sources:
https://www.investopedia.com/terms/c/commoditychannelindex.asp
https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/cci
</summary> */
public class CCI_Series : Single_TBars_Indicator
{
private readonly System.Collections.Generic.List<double> _tp = new();
public CCI_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN)
{
if (_bars.Count > 0) { base.Add(_bars); }
}
public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
{
double _tpItem = (TBar.h + TBar.l + TBar.c) / 3.0;
if (update) { this._tp[this._tp.Count - 1] = _tpItem; } else { this._tp.Add(_tpItem); }
if (this._tp.Count > this._p) { this._tp.RemoveAt(0); }
// average TP over _tp buffer
double _avgTp = _tp.Average();
// average Deviation over _tp buffer
double _avgDv = 0;
for (int i = 0; i < this._tp.Count; i++) { _avgDv += Math.Abs(_avgTp - this._tp[i]); }
_avgDv /= this._tp.Count;
double _cci = (_avgDv == 0) ? double.NaN : (this._tp[this._tp.Count-1] - _avgTp) / (0.015 * _avgDv);
base.Add((TBar.t, _cci), update, _NaN);
}
}
-72
View File
@@ -1,72 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
using System.Runtime.CompilerServices;
/* <summary>
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
</summary> */
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);
}
}
-33
View File
@@ -1,33 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
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.
</summary> */
public class DWMA_Series : Single_TSeries_Indicator {
private readonly System.Collections.Generic.List<double> _buffer1 = new();
private readonly System.Collections.Generic.List<double> _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);
}
}
-71
View File
@@ -1,71 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
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.
</summary> */
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;
}
}
-59
View File
@@ -1,59 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
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/
</summary> */
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);
}
}
-57
View File
@@ -1,57 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
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)
</summary> */
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);
}
}
-119
View File
@@ -1,119 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
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
</summary> */
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<double> _buf1 = new();
private readonly System.Collections.Generic.List<double> _buf2 = new();
private readonly System.Collections.Generic.List<double> _buf3 = new();
private readonly System.Collections.Generic.List<double> _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);
}
}
-127
View File
@@ -1,127 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
JMA: Jurik Moving Average
Mark Jurik's Moving Average (JMA) attempts to eliminate noise to see the
underlying activity. It has extremely low lag, is very smooth and is responsive
to market gaps.
Sources:
https://c.mql5.com/forextsd/forum/164/jurik_1.pdf
https://www.prorealcode.com/prorealtime-indicators/jurik-volatility-bands/
Issues:
Real JMA algorithm is not published and this formula is derived through
deduction and reverse analysis of JMA behavior. It is really close, but not
exact - published JMA tests against JMA.CSV fail with small deviation. The
original algo is slightly different, yet this approximation is close enough.
</summary>
*/
public class JMA_Series : Single_TSeries_Indicator {
private readonly System.Collections.Generic.List<double> volty_short = new();
private readonly System.Collections.Generic.List<double> 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) {
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;
if (this.Count == 0) { prev_ma1 = prev_jma = TValue.v; }
if (update) {
upperBand = p_upperBand;
lowerBand = p_lowerBand;
Kv = p_Kv;
prev_vsum = p_prev_vsum;
prev_ma1 = p_prev_ma1;
prev_det0 = p_prev_det0;
prev_det1 = p_prev_det1;
prev_jma = p_prev_jma;
}
else {
p_upperBand = upperBand;
p_lowerBand = lowerBand;
p_Kv = Kv;
p_prev_vsum = prev_vsum;
p_prev_ma1 = prev_ma1;
p_prev_det0 = prev_det0;
p_prev_det1 = prev_det1;
p_prev_jma = prev_jma;
}
// from Tvalue to volty
del1 = TValue.v - upperBand;
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;
if (Math.Abs(del1) > Math.Abs(del2)) { volty = Math.Abs(del1); }
if (Math.Abs(del1) < Math.Abs(del2)) { volty = Math.Abs(del2); }
//// from volty to avolty
if (update) { volty_short[volty_short.Count - 1] = volty; }
else { volty_short.Add(volty); }
if (volty_short.Count > _voltyS) { volty_short.RemoveAt(0); }
vsum = prev_vsum + 0.1 * (volty - volty_short.First());
prev_vsum = vsum;
if (update) { vsum_buff[vsum_buff.Count - 1] = vsum; }
else { vsum_buff.Add(vsum); }
if (vsum_buff.Count > _voltyL) { vsum_buff.RemoveAt(0); }
double avolty = 0;
for (int i = 0; i < vsum_buff.Count; i++) { avolty += vsum_buff[i]; }
avolty /= vsum_buff.Count;
/// from avolty to rolty
double rvolty = (avolty != 0) ? volty / avolty : 0;
double len1 = (Math.Log(Math.Sqrt(_p)) / Math.Log(2.0)) + 2;
if (len1 < 0) { len1 = 0; }
double pow1 = Math.Max(len1 - 2.0, 0.5);
if (rvolty > Math.Pow(len1, 1.0 / pow1)) { rvolty = Math.Pow(len1, 1.0 / pow1); }
if (rvolty < 1) { rvolty = 1; }
//// from rvolty to second smoothing
double pow2 = Math.Pow(rvolty, pow1);
double beta = 0.45 * (_p - 1) / (0.45 * (_p - 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;
base.Add((TValue.t, jma), update, _NaN);
}
}
-64
View File
@@ -1,64 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
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.
</summary> */
public class KAMA_Series : Single_TSeries_Indicator
{
private readonly double _scFast, _scSlow;
private readonly System.Collections.Generic.List<double> _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);
}
}
+122 -83
View File
@@ -15,105 +15,144 @@ Sources:
</summary> */
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);
}
}
-56
View File
@@ -1,56 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
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.
</summary> */
public class RMA_Series : Single_TSeries_Indicator
{
private readonly System.Collections.Generic.List<double> _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);
}
}
-44
View File
@@ -1,44 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
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()
</summary> */
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;
}
}
-51
View File
@@ -1,51 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
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
</summary> */
public class SMMA_Series : Single_TSeries_Indicator
{
private readonly System.Collections.Generic.List<double> _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);
}
}
-100
View File
@@ -1,100 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
using System.Numerics;
/* <summary>
T3: Tillson T3 Moving Average
Tim Tillson described it in "Technical Analysis of Stocks and Commodities", January 1998 in the
article "Better Moving Averages". Tillsons 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/
</summary> */
public class T3_Series : Single_TSeries_Indicator {
private readonly double _k, _k1m, _c1, _c2, _c3, _c4;
private readonly System.Collections.Generic.List<double> _buffer1 = new();
private readonly System.Collections.Generic.List<double> _buffer2 = new();
private readonly System.Collections.Generic.List<double> _buffer3 = new();
private readonly System.Collections.Generic.List<double> _buffer4 = new();
private readonly System.Collections.Generic.List<double> _buffer5 = new();
private readonly System.Collections.Generic.List<double> _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);
}
}
-70
View File
@@ -1,70 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
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
</summary> */
public class TEMA_Series : Single_TSeries_Indicator
{
private readonly System.Collections.Generic.List<double> _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);
}
}
-43
View File
@@ -1,43 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
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)
</summary> */
public class TRIMA_Series : Single_TSeries_Indicator
{
private readonly System.Collections.Generic.List<double> _buffer1 = new();
private readonly System.Collections.Generic.List<double> _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);
}
}
-75
View File
@@ -1,75 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
using System.Numerics;
/* <summary>
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
</summary> */
public class TRIX_Series : Single_TSeries_Indicator
{
private readonly double _k, _k1m;
private readonly System.Collections.Generic.List<double> _buffer1 = new();
private readonly System.Collections.Generic.List<double> _buffer2 = new();
private readonly System.Collections.Generic.List<double> _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);
}
}
-35
View File
@@ -1,35 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
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
</summary> */
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<double> _buffer = new();
private readonly System.Collections.Generic.List<double> _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);
}
}
-62
View File
@@ -1,62 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
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.
</summary> */
public class ZLEMA_Series : Single_TSeries_Indicator
{
private readonly System.Collections.Generic.List<double> _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);
}
}