Quantower adaptation

This commit is contained in:
Miha Kralj
2022-12-21 07:24:21 -08:00
parent 9f01df0e65
commit 9ad467cd5a
28 changed files with 3493 additions and 3204 deletions
+7 -5
View File
@@ -22,13 +22,15 @@ public class DEMA_Series : Single_TSeries_Indicator
private readonly System.Collections.Generic.List<double> _buffer1 = new();
private readonly System.Collections.Generic.List<double> _buffer2 = new();
private readonly double _k;
private double _lastema1, _lastlastema1;
private readonly bool _useSMA;
private double _lastema1, _lastlastema1;
private double _lastema2, _lastlastema2;
public DEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
public DEMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN)
{
_k = 2.0 / (_p + 1);
if (_data.Count > 0) { base.Add(_data); }
_useSMA = useSMA;
if (_data.Count > 0) { base.Add(_data); }
}
public override void Add((DateTime t, double v) TValue, bool update)
@@ -40,7 +42,7 @@ public class DEMA_Series : Single_TSeries_Indicator
}
double _ema1, _ema2, _dema;
if (this.Count < _p)
if (this.Count < _p && _useSMA)
{
Add_Replace_Trim(_buffer1, TValue.v, _p, update);
_ema1 = 0;
@@ -52,7 +54,7 @@ public class DEMA_Series : Single_TSeries_Indicator
for (int i = 0; i < _buffer2.Count; i++) { _ema2 += _buffer2[i]; }
_ema2 /= _buffer2.Count;
}
else if(this.Count < (2*_p - 1)) // second _p
else if(this.Count < (2*_p - 1) && _useSMA) // second _p
{
_ema1 = (TValue.v - _lastema1) * _k + _lastema1;
+38 -38
View File
@@ -1,39 +1,39 @@
namespace QuanTAlib;
using System;
/* <summary>
DWMA: Double (linearly) Weighted Moving Average
The weights are linearly decreasing over the period and the most recent data has
the heaviest weight.
Sources:
</summary> */
public class DWMA_Series : Single_TSeries_Indicator
{
public DWMA_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> _buffer1 = new();
private readonly System.Collections.Generic.List<double> _buffer2 = 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(_buffer1, TValue.v, _p, update);
double _wma = 0;
for (int i = 0; i < _buffer1.Count; i++) { _wma += _buffer1[i] * this._weights[i]; }
_wma /= (this._buffer1.Count * (this._buffer1.Count + 1)) * 0.5;
Add_Replace_Trim(_buffer2, TValue.v, _p, update);
double _dwma = 0;
for (int i = 0; i < _buffer2.Count; i++) { _dwma += _buffer2[i] * this._weights[i]; }
_dwma /= (this._buffer2.Count * (this._buffer2.Count + 1)) * 0.5;
base.Add((TValue.t, _dwma), update, _NaN);
}
namespace QuanTAlib;
using System;
/* <summary>
DWMA: Double (linearly) Weighted Moving Average
The weights are linearly decreasing over the period and the most recent data has
the heaviest weight.
Sources:
</summary> */
public class DWMA_Series : Single_TSeries_Indicator
{
public DWMA_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> _buffer1 = new();
private readonly System.Collections.Generic.List<double> _buffer2 = 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(_buffer1, TValue.v, _p, update);
double _wma = 0;
for (int i = 0; i < _buffer1.Count; i++) { _wma += _buffer1[i] * this._weights[i]; }
_wma /= (this._buffer1.Count * (this._buffer1.Count + 1)) * 0.5;
Add_Replace_Trim(_buffer2, TValue.v, _p, update);
double _dwma = 0;
for (int i = 0; i < _buffer2.Count; i++) { _dwma += _buffer2[i] * this._weights[i]; }
_dwma /= (this._buffer2.Count * (this._buffer2.Count + 1)) * 0.5;
base.Add((TValue.t, 2*_wma - _dwma), update, _NaN);
}
}
+1 -1
View File
@@ -25,7 +25,7 @@ public class EMA_Series : Single_TSeries_Indicator
private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly double _k, _k1m;
private double _lastema, _lastlastema;
private bool _useSMA;
private readonly bool _useSMA;
public EMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : base(source, period, useNaN)
{
+53 -27
View File
@@ -23,9 +23,11 @@ Issues:
public class JMA_Series : Single_TSeries_Indicator {
private readonly System.Collections.Generic.List<double> volty_10 = new();
private readonly System.Collections.Generic.List<double> vsum_buff = new();
private readonly double pr, beta;
private readonly double pr;
public TSeries mma1 { get; }
public TSeries mma2 { get; }
private double upperBand, lowerBand, _phase, vsum, Kv, del1, del2, prev_del1, prev_del2;
private double upperBand, lowerBand, vsum, Kv, del1, del2;
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;
@@ -35,18 +37,34 @@ public class JMA_Series : Single_TSeries_Indicator {
pr = (phase * 0.01) + 1.5;
if (phase < -100) pr = 0.5;
if (phase > 100) pr = 2.5;
beta = 0.45 * (_p - 1) / (0.45 * (_p - 1) + 2);
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) {
if (this.Count == 0) { prev_ma1 = 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;
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
@@ -59,41 +77,49 @@ public class JMA_Series : Single_TSeries_Indicator {
if (Math.Abs(del1) < Math.Abs(del2)) { volty = Math.Abs(del2); }
//// from volty to avolty
if (update) { volty_10[volty_10.Count - 1] = volty; } else { volty_10.Add(volty); }
if (volty_10.Count > 10) { volty_10.RemoveAt(0); }
if (update) { volty_10[volty_10.Count - 1] = volty; }
else { volty_10.Add(volty); }
if (volty_10.Count > _p) { volty_10.RemoveAt(0); }
vsum = prev_vsum + 0.1 * (volty - volty_10.First());
if (update) { vsum_buff[vsum_buff.Count - 1] = vsum; } else { vsum_buff.Add(vsum); }
if (vsum_buff.Count > 65) vsum_buff.RemoveAt(0);
if (update) { vsum_buff[vsum_buff.Count - 1] = vsum; }
else { vsum_buff.Add(vsum); }
if (vsum_buff.Count > (65))
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 rvolty = (avolty != 0) ? volty / avolty : 0;
double len1 = (Math.Log(Math.Sqrt(0.5 * (_p - 1))) / 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;
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 len2 = Math.Sqrt(0.5 * (_p - 1)) * len1;
Kv = Math.Pow(len2 / (len2 + 1), Math.Sqrt(pow2));
double alpha = Math.Pow(beta, pow2);
double ma1 = (1 - alpha) * TValue.v + alpha * prev_ma1;
Kv = Math.Pow(len2 / (len2 + 2), Math.Sqrt(pow2));
double beta = 0.45 * (_p - 1) / (0.45 * (_p - 1) + 2);
double alpha = Math.Pow(beta * 1.1, pow2);
double ma1 = (1 - alpha) * TValue.v + alpha * prev_ma1;
prev_ma1 = ma1;
double det0 = (1 - beta) * (TValue.v - ma1) + beta * prev_det0;
prev_det0 = det0;
mma1.Add(ma1);
/// from second smoothing to jma
double det0 = (1 - beta) * (TValue.v - ma1) + beta * prev_det0;
prev_det0 = det0;
double ma2 = ma1 + pr * det0;
double det1 = (1 - alpha) * (1 - alpha) * (ma2 - prev_jma) + alpha * alpha * prev_det1;
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);
base.Add((TValue.t, ma1), update, _NaN);
}
}
}
+118 -118
View File
@@ -1,118 +1,118 @@
namespace QuanTAlib;
using System;
/* <summary>
MAMA: MESA Adaptive Moving Average
Created by John Ehlers, the MAMA indicator is a 5-period adaptive moving average of
high/low price that uses classic electrical radio-frequency signal processing algorithms
to reduce noise.
KAMAi = KAMAi - 1 + SC * ( price - KAMAi-1 )
Sources:
https://mesasoftware.com/papers/MAMA.pdf
https://www.tradingview.com/script/foQxLbU3-Ehlers-MESA-Adaptive-Moving-Average-LazyBear/
</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, 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)
{
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;
// 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;
// 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;
// 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;
// phasor addition for 3-bar averaging
i2.i = i1.i - jQ;
q2.i = q1.i + jI;
i2.i = (0.2 * i2.i) + (0.8 * i2.i1); // smoothing it
q2.i = (0.2 * q2.i) + (0.8 * q2.i1);
// homodyne discriminator
re.i = (i2.i * i2.i1) + (q2.i * q2.i1);
im.i = (i2.i * q2.i1) - (q2.i * i2.i1);
re.i = (0.2 * re.i) + (0.8 * re.i1); // smoothing it
im.i = (0.2 * im.i) + (0.8 * im.i1);
// calculate period
pd.i = (im.i != 0 && re.i != 0) ? (6.283185307179586 / Math.Atan(im.i / re.i)) : 0d;
// 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;
// smooth the period
pd.i = (0.2 * pd.i) + (0.8 * pd.i1);
// determine phase position
ph.i = (i1.i != 0) ? Math.Atan(q1.i / i1.i) * 57.29577951308232 : 0;
// change in phase
double delta = Math.Max(ph.i1 - ph.i, 1d);
// adaptive alpha value
double 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, this.Count < this._p - 1 && this._NaN ? double.NaN : fama.i);
Fama.Add(result, update);
}
}
namespace QuanTAlib;
using System;
/* <summary>
MAMA: MESA Adaptive Moving Average
Created by John Ehlers, the MAMA indicator is a 5-period adaptive moving average of
high/low price that uses classic electrical radio-frequency signal processing algorithms
to reduce noise.
KAMAi = KAMAi - 1 + SC * ( price - KAMAi-1 )
Sources:
https://mesasoftware.com/papers/MAMA.pdf
https://www.tradingview.com/script/foQxLbU3-Ehlers-MESA-Adaptive-Moving-Average-LazyBear/
</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, 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)
{
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;
// 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;
// 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;
// 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;
// phasor addition for 3-bar averaging
i2.i = i1.i - jQ;
q2.i = q1.i + jI;
i2.i = (0.2 * i2.i) + (0.8 * i2.i1); // smoothing it
q2.i = (0.2 * q2.i) + (0.8 * q2.i1);
// homodyne discriminator
re.i = (i2.i * i2.i1) + (q2.i * q2.i1);
im.i = (i2.i * q2.i1) - (q2.i * i2.i1);
re.i = (0.2 * re.i) + (0.8 * re.i1); // smoothing it
im.i = (0.2 * im.i) + (0.8 * im.i1);
// calculate period
pd.i = (im.i != 0 && re.i != 0) ? (6.283185307179586 / Math.Atan(im.i / re.i)) : 0d;
// 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;
// smooth the period
pd.i = (0.2 * pd.i) + (0.8 * pd.i1);
// determine phase position
ph.i = (i1.i != 0) ? Math.Atan(q1.i / i1.i) * 57.29577951308232 : 0;
// change in phase
double delta = Math.Max(ph.i1 - ph.i, 1d);
// adaptive alpha value
double 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, this.Count < this._p - 1 && this._NaN ? double.NaN : fama.i);
Fama.Add(result, update);
}
}
+109 -126
View File
@@ -1,127 +1,110 @@
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/
Calculation:
a = 0.7 (but also 0.618);
Ema1 = Ema (Close);
Ema2 = Ema (Ema1);
Ema3 = Ema (Ema2);
Ema4 = Ema (Ema3);
Ema5 = Ema (Ema4);
Ema6 = Ema (Ema5);
T3 = (a*a*a) * Ema6 + (3*a*a + 3*a*a*a) * Ema5 + (6*a*a 3*a 3*a*a*a) * Ema4 + (1 + 3*a + a*a*a + 3*a*a) * Ema3
</summary> */
public class T3_Series : Single_TSeries_Indicator
{
private double k, a;
private double c1, c2, c3, c4;
private double o_c1, o_c2, o_c3, o_c4;
private double e1, e2, e3, e4, e5, e6;
private double o_e1, o_e2, o_e3, o_e4, o_e5, o_e6;
private double sum1, sum2, sum3, sum4, sum5, sum6;
private double o_sum1, o_sum2, o_sum3, o_sum4, o_sum5, o_sum6;
public T3_Series(TSeries source, int period, double vfactor = 0.7, bool useNaN = false) : base(source, period, useNaN)
{
k = 2.0 / (_p + 1);
a = vfactor;
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) + (3 * a * a) + (a * a * a) ;
e1 = e2 = e3 = e4 = e5 = e6 = 0;
sum1 = sum2 = sum3 = sum4 = sum5 = sum6 = 0;
if (_data.Count > 0) { base.Add(data: _data); }
}
public override void Add((DateTime t, double v) TValue, bool update)
{
if (update) {
// roll back (x = oldx)
c1 = o_c1; c2 = o_c2; c3 = o_c3; c4 = o_c4;
e1 = o_e1; e2 = o_e2; e3 = o_e3; e4 = o_e4; e5 = o_e5; e6 = o_e6;
sum1 = o_sum1; sum2 = o_sum2; sum3 = o_sum3; sum4 = o_sum4; sum5 = o_sum5; sum6 = o_sum6;
} else {
// roll forward (oldx = x)
o_c1 = c1; o_c2 = c2; o_c3 = c3; o_c4 = c4;
o_e1 = e1; o_e2 = e2; o_e3 = e3; o_e4 = e4; o_e5 = e5; o_e6 = e6;
o_sum1 = sum1; o_sum2 = sum2; o_sum3 = sum3; o_sum4 = sum4; o_sum5 = sum5; o_sum6 = sum6;
}
double v = TValue.v;
int i = base.Count;
if (i > _p - 1) {
e1 += k * (v - e1);
if (i > 2 * (_p - 1)) {
e2 += k * (e1 - e2);
if (i > 3 * (_p - 1)) {
e3 += k * (e2 - e3);
if (i > 4 * (_p - 1)) {
e4 += k * (e3 - e4);
if (i > 5 * (_p - 1)) {
e5 += k * (e4 - e5);
if (i > 6 * (_p - 1)) {
e6 += k * (e5 - e6);
}
else {
sum6 += e5;
if (i == 6 * (_p - 1)) {
e6 = sum6 / Math.Max(_p, base.Count);
}
}
}
else {
sum5 += e4;
if (i == 5 * (_p - 1)) {
sum6 = e5 = sum5 / Math.Max(_p, base.Count);
}
}
}
else {
sum4 += e3;
if (i == 4 * (_p - 1)) {
sum5 = e4 = sum4 / Math.Max(_p, base.Count);
}
}
}
else {
sum3 += e2;
if (i == 3 * (_p - 1)) {
sum4 = e3 = sum3 / Math.Max(_p, base.Count);
}
}
}
else {
sum2 += e1;
if (i == 2 * (_p - 1)) {
sum3 = e2 = sum2 / Math.Max(_p, base.Count);
}
}
}
else {
sum1 += v;
if (i == _p - 1) {
sum2 = e1 = sum1 / Math.Max(_p, base.Count);
}
}
double t3 = (c1 * e6) + (c2 * e5) + (c3 * e4) + (c4 * e3);
base.Add(TValue: (TValue.t, t3), update: update, useNaN: _NaN);
}
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/
Calculation:
Volume Factor is typically 0.7 (but also 0.618);
Ema1 = Ema (Close);
Ema2 = Ema (Ema1);
Ema3 = Ema (Ema2);
Ema4 = Ema (Ema3);
Ema5 = Ema (Ema4);
Ema6 = Ema (Ema5);
T3 = (a*a*a) * Ema6 + (3*a*a + 3*a*a*a) * Ema5 + (6*a*a 3*a 3*a*a*a) * Ema4 + (1 + 3*a + a*a*a + 3*a*a) * Ema3
</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 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);
}
}
+82
View File
@@ -0,0 +1,82 @@
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.
Calculation:
Ema1 = Ema (Close);
Ema2 = Ema (Ema1);
Ema3 = Ema (Ema2);
TRIX = (Ema3-Ema3[1]) / Ema3[1]
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 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);
}
}