Add new data structures and event handling classes for trading platform. Include base classes, value and bar structs, event arguments, emitters, listeners. Update ruleset for SonarLint.

This commit is contained in:
Miha Kralj
2024-07-25 17:42:09 -07:00
parent f7fd3fbf9f
commit 7dd938c368
86 changed files with 9367 additions and 9153 deletions
+188 -188
View File
@@ -1,189 +1,189 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <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 : TSeries {
private int _len;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private double sumPr;
private 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; }
private double mamaseed, famaseed;
//core constructors
public MAMA_Series(double fastlimit, double slowlimit, bool useNaN) {
_period = (int)(2 / fastlimit) - 1;
fastl = fastlimit;
slowl = slowlimit;
Fama = new TSeries();
_NaN = useNaN;
Name = $"MAMA({_period})";
_len = 0;
}
public MAMA_Series(TSeries source, double fastlimit, double slowlimit, bool useNaN = false) : this(fastlimit, slowlimit, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public MAMA_Series() : this(period: 0, useNaN: false) { }
public MAMA_Series(int period) : this(period, useNaN: false) { }
public MAMA_Series(int period, bool useNaN) : this(fastlimit: 2 / (period + 1), slowlimit: 0.2 / (period + 1), useNaN) {
_period = period;
}
public MAMA_Series(TBars source) : this(source.Close, period: 0, useNaN: false) { }
public MAMA_Series(TBars source, int period) : this(source.Close, period, false) { }
public MAMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public MAMA_Series(TSeries source, int period) : this(source, period, false) { }
public MAMA_Series(TSeries source, int period, bool useNaN) : this(source, fastlimit: 2 / ((double)period + 1), slowlimit: 0.2 / ((double)period + 1), useNaN: useNaN) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN), update);
}
if (!update) {
// 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;
_len++;
}
if (_period == 0) {
fastl = 2 / (double)_len;
slowl = fastl * 0.1;
}
if (_period == 1) {
fastl = 1;
slowl = 1;
}
var i = _len - 1;
pr.i = TValue.v;
if (i > 5) {
var 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
double jI = (0.0962 * i1.i + 0.5769 * i1.i2 - 0.5769 * i1.i4 - 0.0962 * i1.i6) * adj;
double 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
var delta = Math.Max(ph.i1 - ph.i, 1d);
// adaptive alpha value
var alpha = Math.Max(fastl / delta, slowl);
// final indicators
mama.i = alpha * (pr.i - mama.i1) + mama.i1;
fama.i = 0.5d * alpha * (mama.i - fama.i1) + 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);
if (_len == 1) {
mamaseed = famaseed = TValue.v;
}
else {
mamaseed = fastl * (TValue.v - mamaseed) + mamaseed;
famaseed = slowl * (TValue.v - famaseed) + famaseed;
}
}
double _fama = (i > 5) ? fama.i : famaseed;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _fama);
Fama.Add(res, update);
double _mama = (i > 5) ? mama.i : mamaseed;
res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mama);
return base.Add(res, update);
}
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_len = 0;
}
namespace QuanTAlib;
using System;
using System.Linq;
/* <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 : TSeries {
private int _len;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private double sumPr;
private 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; }
private double mamaseed, famaseed;
//core constructors
public MAMA_Series(double fastlimit, double slowlimit, bool useNaN) {
_period = (int)(2 / fastlimit) - 1;
fastl = fastlimit;
slowl = slowlimit;
Fama = new TSeries();
_NaN = useNaN;
Name = $"MAMA({_period})";
_len = 0;
}
public MAMA_Series(TSeries source, double fastlimit, double slowlimit, bool useNaN = false) : this(fastlimit, slowlimit, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public MAMA_Series() : this(period: 0, useNaN: false) { }
public MAMA_Series(int period) : this(period, useNaN: false) { }
public MAMA_Series(int period, bool useNaN) : this(fastlimit: 2 / (period + 1), slowlimit: 0.2 / (period + 1), useNaN) {
_period = period;
}
public MAMA_Series(TBars source) : this(source.Close, period: 0, useNaN: false) { }
public MAMA_Series(TBars source, int period) : this(source.Close, period, false) { }
public MAMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public MAMA_Series(TSeries source, int period) : this(source, period, false) { }
public MAMA_Series(TSeries source, int period, bool useNaN) : this(source, fastlimit: 2 / ((double)period + 1), slowlimit: 0.2 / ((double)period + 1), useNaN: useNaN) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN), update);
}
if (!update) {
// 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;
_len++;
}
if (_period == 0) {
fastl = 2 / (double)_len;
slowl = fastl * 0.1;
}
if (_period == 1) {
fastl = 1;
slowl = 1;
}
var i = _len - 1;
pr.i = TValue.v;
if (i > 5) {
var 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
double jI = (0.0962 * i1.i + 0.5769 * i1.i2 - 0.5769 * i1.i4 - 0.0962 * i1.i6) * adj;
double 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
var delta = Math.Max(ph.i1 - ph.i, 1d);
// adaptive alpha value
var alpha = Math.Max(fastl / delta, slowl);
// final indicators
mama.i = alpha * (pr.i - mama.i1) + mama.i1;
fama.i = 0.5d * alpha * (mama.i - fama.i1) + 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);
if (_len == 1) {
mamaseed = famaseed = TValue.v;
}
else {
mamaseed = fastl * (TValue.v - mamaseed) + mamaseed;
famaseed = slowl * (TValue.v - famaseed) + famaseed;
}
}
double _fama = (i > 5) ? fama.i : famaseed;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _fama);
Fama.Add(res, update);
double _mama = (i > 5) ? mama.i : mamaseed;
res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mama);
return base.Add(res, update);
}
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_len = 0;
}
}