Update main automation workflow to use wildcard for dotcover report path

This commit is contained in:
Miha Kralj
2023-05-04 08:19:57 -07:00
parent 5e7ba2427e
commit 56f8db2949
89 changed files with 1721 additions and 1356 deletions
+5 -3
View File
@@ -65,7 +65,7 @@ jobs:
run: dotnet sonarscanner begin /o:"mihakralj" /k:"mihakralj_QuanTAlib"
/d:sonar.login="${{ secrets.SONAR_TOKEN }}"
/d:sonar.host.url="https://sonarcloud.io"
/d:sonar.cs.dotcover.reportsPaths=./dotcover.xml
/d:sonar.cs.dotcover.reportsPaths=dotcover*
############# Build and test
@@ -80,8 +80,10 @@ jobs:
- name: Build Strategies DLL
run: dotnet build ./Strategies/Strategies.csproj --configuration Release --nologo
- name: DotCover Test
run: dotnet dotcover test Tests/Tests.csproj --dcReportType=DetailedXML --dcReportType=HTML --dcoutput=dotcover.xml --dcoutput=dotcover.html
- name: DotCover Test HTML
run: dotnet dotcover test Tests/Tests.csproj --dcReportType=HTML --dcoutput=./dotcover.html
- name: DotCover Test XML
run: dotnet dotcover test Tests/Tests.csproj --dcReportType=DetailedXML --dcoutput=./dotcover.xml --verbosity=Detailed
- name: Coverlet Test
run: dotnet test -p:CollectCoverage=true --collect:"XPlat Code Coverage" --results-directory "./"
@@ -1,5 +1,6 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
@@ -12,11 +13,16 @@ Sources:
</summary> */
public class COVAR_Series : Pair_TSeries_Indicator
{
public COVAR_Series(TSeries d1, TSeries d2, int period, bool useNaN = false) : base(d1, d2, period, useNaN)
{
if (base._d1.Count > 0 && base._d2.Count > 0) { for (int i = 0; i < base._d1.Count; i++) { this.Add(base._d1[i], base._d2[i], false); } }
if (base._d1.Count > 0 && base._d2.Count > 0) {
for (int i = 0; i < base._d1.Count; i++) {
this.Add(base._d1[i], base._d2[i], false);
}
}
}
private readonly System.Collections.Generic.List<double> _x = new();
@@ -25,9 +31,9 @@ public class COVAR_Series : Pair_TSeries_Indicator
public override void Add((System.DateTime t, double v) TValue1, (System.DateTime t, double v) TValue2, bool update)
{
Add_Replace_Trim(_x, TValue1.v, _p, update);
Add_Replace_Trim(_y, TValue2.v, _p, update);
Add_Replace_Trim(_xy, TValue1.v * TValue2.v, _p, update);
BufferTrim(_x, TValue1.v, _p, update);
BufferTrim(_y, TValue2.v, _p, update);
BufferTrim(_xy, TValue1.v * TValue2.v, _p, update);
double _avgx = _x.Average();
double _avgy = _y.Average();
@@ -37,4 +43,4 @@ public class COVAR_Series : Pair_TSeries_Indicator
var result = (TValue1.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _covar);
if (update) { base[base.Count - 1] = result; } else { base.Add(result); }
}
}
}
-32
View File
@@ -1,32 +0,0 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
MIDPRICE: Midpoint price (highhest high + lowest low)/2 in the given period in the series.
If period = 0 => period = full length of the series
</summary> */
public class MIDPRICE_Series : Single_TBars_Indicator
{
public MIDPRICE_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN)
{
if (base._bars.Count > 0)
{ base.Add(base._bars); }
}
private readonly System.Collections.Generic.List<double> _bufferhi = new();
private readonly System.Collections.Generic.List<double> _bufferlo = new();
public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update)
{
Add_Replace_Trim(_bufferhi, TBar.h, _p, update);
Add_Replace_Trim(_bufferlo, TBar.l, _p, update);
double _max = _bufferhi.Max();
double _min = _bufferlo.Min();
double _mid = (_max + _min) * 0.5;
base.Add((TBar.t, _mid), update, _NaN);
}
}
-40
View File
@@ -1,40 +0,0 @@
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, _cm1_o;
public TR_Series(TBars source, bool useNaN = false) : base(source, period:0, useNaN:useNaN) {
_cm1 =_cm1_o = double.NaN;
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) TBar, bool update)
{
if (update) {_cm1 = _cm1_o; } else { _cm1_o = _cm1; }
if (_cm1 is double.NaN) { _cm1 = TBar.c; } //first bar
double d1 = Math.Abs(TBar.h - TBar.l);
double d2 = Math.Abs(_cm1 - TBar.h);
double d3 = Math.Abs(_cm1 - TBar.l);
var ret = (TBar.t, (base.Count==0 && base._NaN) ? double.NaN : Math.Max(d1,Math.Max(d2,d3)) );
base.Add(ret, update);
_cm1 = TBar.c;
}
}
@@ -16,97 +16,117 @@ Abstract classes with all scaffolding required to build indicators.
</summary> */
public abstract class Pair_TSeries_Indicator : TSeries {
protected readonly int _p;
protected readonly bool _NaN;
protected readonly TSeries _d1;
protected readonly TSeries _d2;
protected readonly double _dd1, _dd2;
public abstract class Pair_TSeries_Indicator : TSeries
{
protected readonly int _p;
protected readonly bool _NaN;
protected readonly TSeries _d1;
protected readonly TSeries _d2;
protected readonly double _dd1, _dd2;
// Chainable Constructors - add them at the end of primary constructors if needed
protected Pair_TSeries_Indicator(TSeries source1, TSeries source2, int period, bool useNaN) {
_p = period;
_NaN = useNaN;
_d1 = source1;
_d2 = source2;
_dd1 = double.NaN;
_dd2 = double.NaN;
_d1.Pub += Sub;
_d2.Pub += Sub;
}
// Chainable Constructors - add them at the end of primary constructors if needed
protected Pair_TSeries_Indicator(TSeries source1, TSeries source2, int period, bool useNaN)
{
this._p = period;
this._NaN = useNaN;
this._d1 = source1;
this._d2 = source2;
this._dd1 = double.NaN;
this._dd2 = double.NaN;
this._d1.Pub += this.Sub;
this._d2.Pub += this.Sub;
}
protected Pair_TSeries_Indicator(TSeries source1, TSeries source2)
{
this._d1 = source1;
this._d2 = source2;
this._dd1 = double.NaN;
this._dd2 = double.NaN;
this._d1.Pub += this.Sub;
this._d2.Pub += this.Sub;
}
protected Pair_TSeries_Indicator(TSeries source1, double dd2)
{
this._d1 = source1;
this._d2 = new();
this._dd1 = double.NaN;
this._dd2 = dd2;
this._d1.Pub += this.Sub;
}
protected Pair_TSeries_Indicator(double dd1, TSeries source2)
{
this._d1 = new();
this._d2 = source2;
this._dd1 = dd1;
this._dd2 = double.NaN;
this._d2.Pub += this.Sub;
}
protected Pair_TSeries_Indicator(TSeries source1, TSeries source2) {
_d1 = source1;
_d2 = source2;
_dd1 = double.NaN;
_dd2 = double.NaN;
_d1.Pub += Sub;
_d2.Pub += Sub;
}
// overridable Add(Tvalue, Tvalue) method to add/update a single value at the end of the list
public virtual void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2, bool update) => base.Add(TValue: (TValue1.t, 0), update: update); // default inserts zeros
protected Pair_TSeries_Indicator(TSeries source1, double dd2) {
_d1 = source1;
_d2 = new TSeries();
_dd1 = double.NaN;
_dd2 = dd2;
_d1.Pub += Sub;
}
// potentially overridable Add() bulk variations (could be replaced with faster bulk algos)
public virtual void Add(TSeries d1, TSeries d2) { for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], d2[i], update: false); }}
public virtual void Add(TSeries d1, double dd2) { for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], (d1[i].t, dd2), update: false); }}
public virtual void Add(double dd1, TSeries d2) { for (int i = 0; i < d2.Count; i++) { this.Add((d2[i].t, dd1), d2[i], update: false); }}
protected Pair_TSeries_Indicator(double dd1, TSeries source2) {
_d1 = new TSeries();
_d2 = source2;
_dd1 = dd1;
_dd2 = double.NaN;
_d2.Pub += Sub;
}
public void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2) => this.Add(TValue1, TValue2, update: false);
// overridable Add(Tvalue, Tvalue) method to add/update a single value at the end of the list
public virtual void Add((DateTime t, double v) TValue1, (DateTime t, double v) TValue2, bool update) {
base.Add((TValue1.t, 0), update);
// default inserts zeros
}
public void Add(bool update)
{
if ((this._dd1 is double.NaN) && (this._dd2 is double.NaN))
{
// (Series, Series)
if (update || (this._d1.Count > this.Count && this._d2.Count > this.Count))
{ this.Add(this._d1[this._d1.Count - 1], this._d2[this._d2.Count - 1], update); }
}
else if ((this._dd2 is not double.NaN) && (this._dd1 is double.NaN))
{
// (Series, Double)
this.Add(TValue1: this._d1[this._d1.Count - 1], TValue2: (this._d1[this._d1.Count - 1].t, this._dd2), update: update);
}
else
{
// (Double, Series)
this.Add(TValue1: (this._d2[this._d2.Count - 1].t, this._dd1), TValue2: this._d2[this._d2.Count - 1], update: update);
// potentially overridable Add() bulk variations (could be replaced with faster bulk algos)
public virtual void Add(TSeries d1, TSeries d2) {
for (var i = 0; i < d1.Count; i++) {
Add(d1[i], d2[i], false);
}
}
public void Add() => this.Add(update: false);
public new void Sub(object source, TSeriesEventArgs e) => this.Add(e.update);
public virtual void Add(TSeries d1, double dd2) {
for (var i = 0; i < d1.Count; i++) {
Add(d1[i], (d1[i].t, dd2), false);
}
}
protected static void Add_Replace(List<double> l, double v, bool update)
{
if (update)
{ l[l.Count - 1] = v; }
else
{ l.Add(v); }
}
protected static void Add_Replace_Trim(List<double> l, double v, int p, bool update)
{
Add_Replace(l, v, update);
if (l.Count > p && p != 0)
{ l.RemoveAt(0); }
}
public virtual void Add(double dd1, TSeries d2) {
for (var i = 0; i < d2.Count; i++) {
Add((d2[i].t, dd1), d2[i], false);
}
}
public void Add((DateTime t, double v) TValue1, (DateTime t, double v) TValue2) {
Add(TValue1, TValue2, false);
}
public void Add(bool update) {
if (_dd1 is double.NaN && _dd2 is double.NaN) {
// (Series, Series)
if (update || (_d1.Count > Count && _d2.Count > Count)) {
Add(_d1[_d1.Count - 1], _d2[_d2.Count - 1], update);
}
}
else if (_dd2 is not double.NaN && _dd1 is double.NaN) {
// (Series, Double)
Add(_d1[_d1.Count - 1], (_d1[_d1.Count - 1].t, _dd2), update);
}
else {
// (Double, Series)
Add((_d2[_d2.Count - 1].t, _dd1), _d2[_d2.Count - 1], update);
}
}
public void Add() {
Add(false);
}
public new void Sub(object source, TSeriesEventArgs e) {
Add(e.update);
}
protected static void Add_Replace(List<double> l, double v, bool update) {
if (update) {
l[l.Count - 1] = v;
}
else {
l.Add(v);
}
}
protected static void Add_Replace_Trim(List<double> l, double v, int p, bool update) {
Add_Replace(l, v, update);
if (l.Count > p && p != 0) {
l.RemoveAt(0);
}
}
}
@@ -1,67 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <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_TBars_Indicator : TSeries
{
protected readonly int _p;
protected readonly bool _NaN;
protected readonly TBars _bars;
// Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN)
protected Single_TBars_Indicator(TBars source, int period, bool useNaN)
{
this._p = period;
this._bars = source;
this._NaN = useNaN;
this._bars.Pub += this.Sub;
}
// overridable Add() method to add/update a single item at the end of the list
public virtual void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar, bool update) => base.Add((TBar.t, 0.0), update);
public virtual void Add((System.DateTime t, double v) TValue, bool update, bool useNaN)
{
var res = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : TValue.v);
base.Add(res, update);
}
// potentially overridable Add() method for the whole bars or series (could be replaced with faster bulk algo)
public virtual void Add(TBars bars) { for (int i = 0; i < bars.Count; i++) { this.Add(TBar: bars[i], update: false); } }
public virtual new void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { base.Add(TValue: data[i], update: false); } }
public void Add((System.DateTime t, double o, double h, double l, double c, double v) TBar) => this.Add(TBar: TBar, update: false);
public void Add(bool update) => this.Add(TBar: this._bars[this._bars.Count - 1], update: update);
public void Add() => this.Add(TBar: this._bars[this._bars.Count - 1], update: false);
public new void Sub(object source, TSeriesEventArgs e) => this.Add(TBar: this._bars[this._bars.Count - 1], update: e.update);
protected static void Add_Replace(List<double> l, double v, bool update)
{
if (update)
{ l[l.Count - 1] = v; }
else
{ l.Add(v); }
}
protected static void Add_Replace_Trim(List<double> l, double v, int p, bool update)
{
Add_Replace(l, v, update);
if (l.Count > p && p != 0)
{ l.RemoveAt(0); }
}
}
@@ -1,73 +0,0 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <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
{
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
protected int _p;
// Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN)
protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN)
{
_data = source;
_period = period;
_p = _period;
_NaN = useNaN;
_data.Pub += Sub;
}
// overridable Add() method to add/update a single item at the end of the list
public virtual void Add((DateTime t, double v) TValue, bool update, bool useNaN)
{
if (_period == 0) { _p = Length; }
var res = (TValue.t, Count < _p - 1 && _NaN ? double.NaN : TValue.v);
base.Add(res, update);
}
public new virtual void Add((DateTime t, double v) TValue, bool update) => base.Add(TValue, update);
// potentially overridable Add() method for the whole series (could be replaced with faster bulk algo)
public virtual new void Add(TSeries data)
{
foreach (var item in data) { Add(TValue: item, update: false); }
}
public new void Add((System.DateTime t, double v) TValue) => this.Add(TValue: TValue, update: false);
public void Add(bool update) => this.Add(TValue: this._data[this._data.Count - 1], update: update);
public void Add() => this.Add(TValue: this._data[this._data.Count - 1], update: false);
public new void Sub(object source, TSeriesEventArgs e) => this.Add(TValue: this._data[this._data.Count - 1], update: e.update);
protected static void Add_Replace(List<double> l, double v, bool update)
{
if (update)
{ l[l.Count - 1] = v; }
else
{ l.Add(v); }
}
protected static double Add_Replace_Trim(List<double> l, double v, int p, bool update)
{
Add_Replace(l, v, update);
double ret = (l.Count > 0) ? l.First() : 0;
if (l.Count > p && p != 0)
{
l.RemoveAt(0);
}
return ret;
}
}
+5 -1
View File
@@ -12,6 +12,8 @@ EQUITY - Generates P&L portfolio based on trades signals and equity prices
//optional: long, short, long&short
//optional: warmup period: warmup
/*
public class EQUITY_Series : Single_TSeries_Indicator {
readonly TSeries inmarket; //for every bar
private readonly TSeries _price;
@@ -84,4 +86,6 @@ public class EQUITY_Series : Single_TSeries_Indicator {
inmarket.Add((TValue.t, (double)_inmarket));
base.Add((TValue.t, _equity), update, _NaN);
}
}
}
*/
-93
View File
@@ -1,93 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
LINREG: Linear Regression (using Least Square Method)
Linear Regression provides a slope of a straight line that is the best approximation of the given set of data.
The method of least squares is a standard approach in linear regression analysis to approximate the solution
by minimizing the sum of the squares of the residuals made in the results of each individual equation.
Additional outputs provided by LINREG:
.Intercept - y-intercept point of the best fit line
.RSquared - R-Squared (R²), Coefficient of Determination
.StdDev - Standard Deviation of data over given periods
y = Slope * x + Intercept
Sources:
https://en.wikipedia.org/wiki/Least_squares
</summary> */
public class LINREG_Series : Single_TSeries_Indicator
{
private readonly TSeries p_Intercept = new();
private readonly TSeries p_RSquared = new();
private readonly TSeries p_StdDev = new();
private readonly System.Collections.Generic.List<double> _buffer = new();
public TSeries Intercept => p_Intercept;
public TSeries RSquared => p_RSquared;
public TSeries StdDev => p_StdDev;
public LINREG_Series(TSeries source, int period, bool useNaN = false)
: base(source, period, useNaN)
{
if (this._data.Count > 0) { base.Add(this._data); }
}
public override void Add((System.DateTime t, double v) TValue, bool update)
{
Add_Replace_Trim(_buffer, TValue.v, _p, update);
int _len = this._buffer.Count;
// get averages for period
double sumX = 0;
double sumY = 0;
for (int p = 0; p < _len; p++)
{
sumX += this.Count - _len + 2 + p;
sumY += _buffer[p];
}
double avgX = sumX / _len;
double avgY = sumY / _len;
// least squares method
double sumSqX = 0;
double sumSqY = 0;
double sumSqXY = 0;
for (int p = 0; p < _len; p++)
{
double devX = this.Count - _len + 2 + p - avgX;
double devY = _buffer[p] - avgY;
sumSqX += devX * devX;
sumSqY += devY * devY;
sumSqXY += devX * devY;
}
double _slope = sumSqXY / sumSqX;
double _intercept = avgY - (_slope * avgX);
// calculate Standard Deviation and R-Squared
double stdDevX = Math.Sqrt(sumSqX / _len);
double stdDevY = Math.Sqrt(sumSqY / _len);
double _StdDev = stdDevY;
double arrr = (stdDevX * stdDevY != 0) ? sumSqXY / (stdDevX * stdDevY) / _len : 0;
double _RSquared = arrr * arrr;
var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _slope);
base.Add(ret, update, _NaN);
ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _intercept);
p_Intercept.Add(ret, update);
ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _StdDev);
p_StdDev.Add(ret, update);
ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _RSquared);
p_RSquared.Add(ret, update);
}
}
-49
View File
@@ -1,49 +0,0 @@
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);
}
}
-57
View File
@@ -1,57 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
HWMA: Holt-Winter Moving Average
Indicator HWMA (Holt-Winter Moving Average) is a three-parameter moving
average by the Holt-Winter method; Holt-Winters Exponential Smoothing is
used for forecasting time series data that exhibits both a trend and a
seasonal variation.
Sources:
https://timeseriesreasoning.com/contents/holt-winters-exponential-smoothing/
https://www.mql5.com/en/code/20856
nA - smoothed series (from 0 to 1)
nB - assess the trend (from 0 to 1)
nC - assess seasonality (from 0 to 1)
F[i] = (1-nA) * (F[i-1] + V[i-1] + 0.5 * A[i-1]) + nA * Price[i]
V[i] = (1-nB) * (V[i-1] + A[i-1]) + nB * (F[i] - F[i-1])
A[i] = (1-nC) * A[i-1] + nC * (V[i] - V[i-1])
HWMA[i] = F[i] + V[i] + 0.5 * A[i]
</summary> */
public class HWMA_Series : Single_TSeries_Indicator {
readonly double _nA, _nB, _nC;
double _pF, _pV, _pA;
double _ppF, _ppV, _ppA;
public HWMA_Series(TSeries source, double nA = 0.2, double nB = 0.1, double nC = 0.1, bool useNaN = false) : base(source, 0, useNaN) {
_nA = nA;
_nB = nB;
_nC = nC;
if (this._data.Count > 0) { base.Add(this._data); }
}
public override void Add((DateTime t, double v) TValue, bool update) {
double _F, _V, _A;
if (this.Count == 0) { _pF = TValue.v; _pA = _pV = 0; }
if (update) { _pF = _ppF; _pV = _ppV; _pA = _ppA; }
else { _ppF = _pF; _ppV = _pV; _ppA = _pA; }
_F = (1 - _nA) * (_pF + _pV + 0.5 * _pA) + _nA * TValue.v;
_V = (1 - _nB) * (_pV + _pA) + _nB * (_F - _pF);
_A = (1 - _nC) * _pA + _nC * (_V - _pV);
double _hwma = _F + _V + 0.5 * _A;
_pF = _F;
_pV = _V;
_pA = _A;
base.Add((TValue.t, _hwma), update, _NaN);
}
}
-45
View File
@@ -1,45 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
MACD: Moving Average Convergence/Divergence
Moving average convergence divergence (MACD) is a trend-following momentum
indicator that shows the relationship between two moving averages of a series.
The MACD is calculated by subtracting the 26-period exponential moving average (EMA)
from the 12-period EMA. MACD Signal is 9-day EMA of MACD.
Sources:
https://www.investopedia.com/terms/m/macd.asp
https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/macd
</summary> */
public class MACD_Series : Single_TSeries_Indicator
{
private readonly EMA_Series _TSslow;
private readonly EMA_Series _TSfast;
private readonly SUB_Series _TSmacd;
public EMA_Series Signal { get; }
public MACD_Series(TSeries source, int slow = 26, int fast = 12, int signal = 9, bool useNaN = false)
: base(source, period: 0, useNaN)
{
_TSslow = new(source: source, period: slow, useNaN: false);
_TSfast = new(source: source, period: fast, useNaN: false);
_TSmacd = new(_TSfast, _TSslow);
this.Signal = new(source: _TSmacd, period: signal, useNaN: useNaN);
if (source.Count > 0) { base.Add(_TSmacd); }
}
public override void Add((System.DateTime t, double v) TValue, bool update)
{
double _macd;
if (update)
{
_TSslow.Add(TValue, true);
_TSfast.Add(TValue, true);
}
_macd = this._TSmacd[(this.Count < this._TSmacd.Count) ? this.Count : this._TSmacd.Count - 1].v;
base.Add((TValue.t, _macd), update, _NaN);
}
}
-158
View File
@@ -1,158 +0,0 @@
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, 5, useNaN) {
fastl = fastlimit;
slowl = slowlimit;
Fama = new TSeries();
if (_data.Count > 0) {
base.Add(_data);
}
}
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; }
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;
}
var i = Count;
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
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
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 + (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);
}
}
-40
View File
@@ -1,40 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
ADL: Chaikin Accumulation/Distribution Line
ADL is a volume-based indicator that measures the cumulative Money Flow Volume:
1. Money Flow Multiplier = [(Close - Low) - (High - Close)] /(High - Low)
2. Money Flow Volume = Money Flow Multiplier x Volume for the Period
3. ADL = Previous ADL + Current Period's Money Flow Volume
Sources:
https://school.stockcharts.com/doku.php?id=technical_indicators:accumulation_distribution_line
</summary> */
public class ADL_Series : Single_TBars_Indicator
{
private double _lastadl, _lastlastadl;
public ADL_Series(TBars source, bool useNaN = false) : base(source, 0, useNaN)
{
_lastadl = _lastlastadl = 0;
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)
{
if (update) { this._lastadl = this._lastlastadl; }
double _adl = 0;
double tmp = TBar.h - TBar.l;
if (tmp > 0.0 ) { _adl = _lastadl + ((2*TBar.c - TBar.l - TBar.h) / tmp * TBar.v); }
this._lastlastadl = this._lastadl;
this._lastadl = _adl;
base.Add((TBar.t, _adl), update, _NaN);
}
}
-55
View File
@@ -1,55 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
ADO: Chaikin Accumulation/Distribution Oscillator
ADO measures the momentum of ADL using the difference between slow (10-day) EMA(ADL)
and fast (3-day) EMA(ADL):
Chaikin A/D Oscillator is defined as 3-day EMA of ADL minus 10-day EMA of ADL
Sources:
https://school.stockcharts.com/doku.php?id=technical_indicators:chaikin_oscillator
</summary> */
public class ADOSC_Series : Single_TBars_Indicator
{
private readonly double _k1, _k2;
private double _lastema1, _lastlastema1, _lastema2, _lastlastema2;
private double _lastadl, _lastlastadl;
public ADOSC_Series(TBars source, int shortPeriod = 3, int longPeriod =10, bool useNaN = false) : base(source, period: 0, useNaN)
{
_k1 = 2.0 / (shortPeriod + 1);
_k2 = 2.0 / (longPeriod + 1);
_lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
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)
{
if (update) {
_lastadl = _lastlastadl;
_lastema1 = _lastlastema1;
_lastema2 = _lastlastema2;
}
double _adl = 0;
double tmp = TBar.h - TBar.l;
if (tmp > 0.0) { _adl = _lastadl + ((2 * TBar.c - TBar.l - TBar.h) / tmp * TBar.v); }
if (this.Count == 0) { _lastema1 = _lastema2 = _adl; }
double _ema1 = (_adl - _lastema1) * _k1 + _lastema1;
double _ema2 = (_adl - _lastema2) * _k2 + _lastema2;
_lastlastadl = _lastadl; _lastadl = _adl;
_lastlastema1 = _lastema1; _lastema1 = _ema1;
_lastlastema2 = _lastema2; _lastema2 = _ema2;
double _adosc = _ema1 - _ema2;
base.Add((TBar.t, _adosc), update, _NaN);
}
}
-48
View File
@@ -1,48 +0,0 @@
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;
private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
private readonly int _period;
public ATRP_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) {
_period = period;
_k = 1.0 / (double)(_period);
_lastatr = _lastlastatr = _cm1 = _lastcm1 = _sum = _oldsum = 0;
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) TBar, bool update) {
if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
else { _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum; }
if (this.Count == 0) { _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)));
_cm1 = TBar.c;
double _atr = 0;
if (this.Count == 0) { _atr = d.v; }
else if (this.Count < _p + 1) { _sum += d.v; _atr = _sum / (this.Count); }
else { _atr = _k * (d.v - _lastatr) + _lastatr; }
_lastatr = _atr;
double _atrp = 100 * (_atr / TBar.c);
var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atrp);
base.Add(ret, update);
}
}
-49
View File
@@ -1,49 +0,0 @@
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;
private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
private readonly int _period;
public ATR_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) {
_period = period;
_k = 1.0 / (double)(_p);
_lastatr = _lastlastatr = _cm1 = _lastcm1 = _sum = _oldsum = 0;
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) TBar, bool update) {
if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
else { _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum; }
if (this.Count == 0) { _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)));
_cm1 = TBar.c;
double _atr = 0;
if (this.Count == 0) { _atr = d.v; }
else if (this.Count < _p + 1) { _sum += d.v; _atr = _sum / (this.Count); }
else { _atr = _k * (d.v - _lastatr) + _lastatr; }
_lastatr = _atr;
var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atr);
base.Add(ret, update);
}
}
-73
View File
@@ -1,73 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
BBANDS: Bollinger Bands®
Price channels created by John Bollinger, depict volatility as standard deviation boundary
line range from a moving average of price. The bands automatically widen when volatility
increases and contract when volatility decreases. Their dynamic nature allows them to be
used on different securities with the standard settings.
Mid Band = simple moving average (SMA)
Upper Band = SMA + (standard deviation of price x multiplier)
Lower Band = SMA - (standard deviation of price x multiplier)
Bandwidth = Width of the channel: (Upper-Lower)/SMA
%B = The location of the data point within the channel: (Price-Lower)/(Upper/Lower)
Z-Score = number of standard deviations of the data point from SMA
Sources:
https://www.investopedia.com/terms/b/bollingerbands.asp
https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands
Note:
Bollinger Bands® is a registered trademark of John A. Bollinger.
</summary> */
public class BBANDS_Series : Single_TSeries_Indicator
{
public SMA_Series Mid { get; }
public ADD_Series Upper { get; }
public SUB_Series Lower { get; }
public DIV_Series PercentB { get; }
public DIV_Series Bandwidth { get; }
public DIV_Series Zscore { get; }
private readonly SDEV_Series _sdev;
private readonly MUL_Series _mulsdev;
private readonly SUB_Series _pbdnd;
private readonly SUB_Series _pbdvr;
private readonly SUB_Series _zdnd;
public BBANDS_Series(TSeries source, int period = 26, double multiplier = 2.0, bool useNaN = false)
: base(source, period: 0, useNaN)
{
this.Mid = new(source: source, period: period, useNaN: useNaN);
_sdev = new(source, period, useNaN: useNaN);
_mulsdev = new(_sdev, multiplier);
this.Upper = new(Mid, _mulsdev);
this.Lower = new(Mid, _mulsdev);
_pbdnd = new(source, Lower);
_pbdvr = new(Upper, Lower);
this.PercentB = new(_pbdnd, _pbdvr);
this.Bandwidth = new(_pbdvr, Mid);
_zdnd = new(source, Mid);
this.Zscore = new(_zdnd, _sdev);
if (source.Count > 0)
{ base.Add(this.Bandwidth); }
}
public override void Add((System.DateTime t, double v) TValue, bool update)
{
double _bbandwidth;
if (update)
{ _sdev.Add(TValue, true); }
_bbandwidth = this.Bandwidth[(this.Count < this.Bandwidth.Count) ? this.Count : this.Bandwidth.Count - 1].v;
var result = (TValue.t, _bbandwidth);
base.Add(result, update);
}
}
-59
View File
@@ -1,59 +0,0 @@
namespace QuanTAlib;
using System;
/* <summary>
OBV: On-Balance Volume
On-balance volume (OBV) is a technical trading momentum indicator that uses volume flow to predict
changes in stock price. Joseph Granville first developed the OBV metric in the 1963 book
Granville's New Key to Stock Market Profits.
| +volume; if close > close[previous]
OBV = OBV[previous] + | 0; if close = close[previous]
| -volume; if close < close[previous]
Sources:
https://www.investopedia.com/terms/o/onbalancevolume.asp
https://www.tradingview.com/wiki/On_Balance_Volume_(OBV)
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/on-balance-volume-obv/
https://www.motivewave.com/studies/on_balance_volume.htm
Note:
There is no consensus on what is the first OBV value in the series:
- TA-LIB uses the first volume: OBV[0] = volume[0]
- Skender stock library uses 0: OBV[0] = 0
</summary> */
public class OBV_Series : Single_TBars_Indicator
{
private double _lastobv, _lastlastobv;
private double _lastclose, _lastlastclose;
public OBV_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN)
{
this._lastobv = this._lastlastobv = 0;
this._lastclose = this._lastlastclose = 0;
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)
{
if (update)
{
this._lastobv = this._lastlastobv;
this._lastclose = this._lastlastclose;
}
double _obv = this._lastobv;
if (TBar.c > this._lastclose) { _obv += TBar.v; }
if (TBar.c < this._lastclose) { _obv -= TBar.v; }
this._lastlastobv = this._lastobv;
this._lastobv = _obv;
this._lastlastclose = this._lastclose;
this._lastclose = TBar.c;
var result = (TBar.t, (this.Count < this._p && this._NaN) ? double.NaN : _obv);
base.Add(result, update);
}
}
+69
View File
@@ -0,0 +1,69 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
ADL: Chaikin Accumulation/Distribution Line
ADL is a volume-based indicator that measures the cumulative Money Flow Volume:
1. Money Flow Multiplier = [(Close - Low) - (High - Close)] /(High - Low)
2. Money Flow Volume = Money Flow Multiplier x Volume for the Period
3. ADL = Previous ADL + Current Period's Money Flow Volume
Sources:
https://school.stockcharts.com/doku.php?id=technical_indicators:accumulation_distribution_line
</summary> */
public class ADL_Series : TSeries {
protected readonly TBars _data;
private double _lastadl, _lastlastadl;
//core constructors
public ADL_Series() {
Name = $"ADL()";
_lastadl = _lastlastadl = 0;
}
public ADL_Series(TBars source) {
_data = source;
Name = $"ADL({(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_lastadl = _lastlastadl = 0;
_data.Pub += Sub;
Add(data: _data);
}
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) { this._lastadl = this._lastlastadl; }
else { this._lastlastadl = this._lastadl; }
double _adl = 0;
double tmp = TBar.h - TBar.l;
if (tmp > 0.0) {
_adl = _lastadl + ((2 * TBar.c - TBar.l - TBar.h) / tmp * TBar.v);
}
_lastadl = _adl;
var ret = (TBar.t, _adl);
return base.Add(ret, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_lastadl = _lastlastadl = 0;
}
}
+90
View File
@@ -0,0 +1,90 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
ADOSC: Chaikin Accumulation/Distribution Oscillator
ADO measures the momentum of ADL using the difference between slow (10-day) EMA(ADL)
and fast (3-day) EMA(ADL):
Chaikin A/D Oscillator is defined as 3-day EMA of ADL minus 10-day EMA of ADL
Sources:
https://school.stockcharts.com/doku.php?id=technical_indicators:chaikin_oscillator
</summary> */
public class ADOSC_Series : TSeries {
protected readonly TBars _data;
private readonly double _k1, _k2;
private double _lastema1, _lastlastema1, _lastema2, _lastlastema2;
private double _lastadl, _lastlastadl;
//core constructors
public ADOSC_Series(int shortPeriod, int longPeriod, bool useNaN = false) {
Name = $"ADOSC()";
_k1 = 2.0 / (shortPeriod + 1);
_k2 = 2.0 / (longPeriod + 1);
_lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
}
public ADOSC_Series(TBars source, int shortPeriod, int longPeriod, bool useNaN = false) :this(shortPeriod, longPeriod, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_lastadl = _lastlastadl = 0;
_data.Pub += Sub;
Add(data: _data);
}
public ADOSC_Series() : this(shortPeriod: 3, longPeriod: 10, useNaN: false) {}
public ADOSC_Series(TBars source) : this(source, shortPeriod: 3, longPeriod:10, useNaN:false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update= false) {
if (update) {
_lastadl = _lastlastadl;
_lastema1 = _lastlastema1;
_lastema2 = _lastlastema2;
}
double _adl = 0;
double tmp = TBar.h - TBar.l;
if (tmp > 0.0) { _adl = _lastadl + ((2 * TBar.c - TBar.l - TBar.h) / tmp * TBar.v); }
if (this.Count == 0) { _lastema1 = _lastema2 = _adl; }
double _ema1 = (_adl - _lastema1) * _k1 + _lastema1;
double _ema2 = (_adl - _lastema2) * _k2 + _lastema2;
_lastlastadl = _lastadl;
_lastadl = _adl;
_lastlastema1 = _lastema1;
_lastema1 = _ema1;
_lastlastema2 = _lastema2;
_lastema2 = _ema2;
double _adosc = _ema1 - _ema2;
var ret = (TBar.t, _adosc);
return base.Add(ret, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
}
}
+38 -31
View File
@@ -25,12 +25,12 @@ public class ALMA_Series : TSeries {
protected readonly TSeries _data;
private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly System.Collections.Generic.List<double> _weight = new();
private readonly System.Collections.Generic.List<double> _weight;
private double _norm;
private readonly double _offset, _sigma;
//core constructors
public ALMA_Series(int period, double offset, double sigma, bool useNaN) : base() {
public ALMA_Series(int period, double offset, double sigma, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"ALMA({period})";
@@ -55,36 +55,41 @@ public class ALMA_Series : TSeries {
public ALMA_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, offset: 0.85, sigma: 6.0, useNaN: useNaN) { }
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update=false) {
BufferTrim(_buffer, TValue.v, _period, update);
if (_weight.Count < _buffer.Count) {
for (int i = 0; i < (_buffer.Count - _weight.Count); i++) { _weight.Add(0.0); }
}
if (this._buffer.Count <= _period || _period ==0) {
int _len = this._buffer.Count;
_norm = 0;
double _m = _offset * (_len - 1);
double _s = _len / _sigma;
for (int i = 0; i < _len; i++) {
double _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s));
_weight[i] = _wt;
_norm += _wt;
}
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, double.NaN), update);
}
double _weightedSum = 0;
for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; }
double _alma = _weightedSum / _norm;
BufferTrim(_buffer, TValue.v, _period, update);
if (_weight.Count < _buffer.Count) {
for (var i = 0; i < _buffer.Count - _weight.Count; i++) {
_weight.Add(0.0);
}
}
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _alma);
return base.Add(res, update);
}
if (_buffer.Count <= _period || _period == 0) {
var _len = _buffer.Count;
_norm = 0;
var _m = _offset * (_len - 1);
var _s = _len / _sigma;
for (var i = 0; i < _len; i++) {
var _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s));
_weight[i] = _wt;
_norm += _wt;
}
}
//reset calculation
public override void Reset() {
_buffer.Clear();
_weight.Clear();
}
double _weightedSum = 0;
for (var i = 0; i < _buffer.Count; i++) {
_weightedSum += _weight[i] * _buffer[i];
}
var _alma = _weightedSum / _norm;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _alma);
return base.Add(res, update);
}
//variation of Add()
public override (DateTime t, double v) Add(TSeries data) {
@@ -92,9 +97,6 @@ public class ALMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
@@ -104,4 +106,9 @@ public class ALMA_Series : TSeries {
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
_weight.Clear();
}
}
+87
View File
@@ -0,0 +1,87 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <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 : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TBars _data;
private double _k;
private int _len;
private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
//core constructors
public ATRP_Series(int period, bool useNaN) {
_period = period;
_k = 1.0 / (double)(_period);
_NaN = useNaN;
_len = 0;
Name = $"ATRP({period})";
}
public ATRP_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(data: _data);
}
public ATRP_Series() : this(period: 1, useNaN: false) { }
public ATRP_Series(int period) : this(period: period, useNaN: false) { }
public ATRP_Series(TBars source) : this(source, period: 1, useNaN: false) { }
public ATRP_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
else {
_lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum;
_k = (_period == 0) ? 1 / (double)_len : _k;
_len++;
}
if (_len == 1) { _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)));
_cm1 = TBar.c;
double _atr = 0;
if (this.Count == 0) { _atr = d.v; }
else if (this.Count < _period + 1) { _sum += d.v; _atr = _sum / (this.Count); }
else { _atr = _k * (d.v - _lastatr) + _lastatr; }
_lastatr = _atr;
double _atrp = 100 * (_atr / TBar.c);
var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _atrp);
return base.Add(res, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_len = 0;
}
}
+88
View File
@@ -0,0 +1,88 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <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 : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TBars _data;
private double _k;
private int _len;
private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
//core constructors
public ATR_Series(int period, bool useNaN) {
_period = period;
_k = 1.0 / (double)(_period);
_NaN = useNaN;
_len = 0;
Name = $"ATR({period})";
}
public ATR_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(data: _data);
}
public ATR_Series() : this(period: 1, useNaN: false) { }
public ATR_Series(int period) : this(period: period, useNaN: false) { }
public ATR_Series(TBars source) : this(source, period: 1, useNaN: false) { }
public ATR_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
else {
_lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum;
_k = (_period == 0) ? 1 / (double)_len : _k;
_len++;
}
if (_len == 1) { _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)));
_cm1 = TBar.c;
double _atr = 0;
if (this.Count == 0) { _atr = d.v; }
else if (this.Count < _period + 1) { _sum += d.v; _atr = _sum / (this.Count); }
else { _atr = _k * (d.v - _lastatr) + _lastatr; }
_lastatr = _atr;
var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _atr);
return base.Add(res, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_len = 0;
}
}
+112
View File
@@ -0,0 +1,112 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
BBANDS: Bollinger Bands®
Price channels created by John Bollinger, depict volatility as standard deviation boundary
line range from a moving average of price. The bands automatically widen when volatility
increases and contract when volatility decreases. Their dynamic nature allows them to be
used on different securities with the standard settings.
Mid Band = simple moving average (SMA)
Upper Band = SMA + (standard deviation of price x multiplier)
Lower Band = SMA - (standard deviation of price x multiplier)
Bandwidth = Width of the channel: (Upper-Lower)/SMA
%B = The location of the data point within the channel: (Price-Lower)/(Upper/Lower)
Z-Score = number of standard deviations of the data point from SMA
Sources:
https://www.investopedia.com/terms/b/bollingerbands.asp
https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands
Note:
Bollinger Bands® is a registered trademark of John A. Bollinger.
</summary> */
public class BBANDS_Series : TSeries {
protected readonly int _period;
protected readonly double _multiplier;
protected readonly bool _NaN;
protected readonly TSeries _data;
public SMA_Series Mid { get; }
public TSeries Upper { get; }
public TSeries Lower { get; }
public TSeries PercentB { get; }
public TSeries Bandwidth { get; }
public TSeries Zscore { get; }
private readonly SDEV_Series _sdev;
//core constructors
public BBANDS_Series(int period, double multiplier, bool useNaN) {
_period = period;
_multiplier = multiplier;
_NaN = useNaN;
Name = $"BBANDS({period})";
}
public BBANDS_Series(TSeries source, int period, double multiplier, bool useNaN) : this(period, multiplier, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
Upper = new("BB_Up");
Lower = new("BB_Low");
Bandwidth = new("BBandwidth");
PercentB = new("%BBandwidth");
Zscore = new("Zscore");
Mid = new(period, false);
_sdev = new(period, false);
_data.Pub += Sub;
Add(_data);
}
public BBANDS_Series() : this(period:0, multiplier: 2.0, useNaN: false) { }
public BBANDS_Series(int period) : this(period: period, multiplier: 2.0, useNaN:false) { }
public BBANDS_Series(TBars source) : this(source:source.Close, period:0, multiplier: 2.0, useNaN:false) { }
public BBANDS_Series(TBars source, int period) : this(source:source.Close, period:period, multiplier: 2.0, useNaN: false) { }
public BBANDS_Series(TBars source, int period, double multiplier, bool useNaN) : this(source.Close, period:period, multiplier:multiplier, useNaN: false) { }
public BBANDS_Series(TSeries source) : this(source, period:0, useNaN:false) { }
public BBANDS_Series(TSeries source, int period) : this(source:source, period:period, useNaN:false) { }
public BBANDS_Series(TSeries source, int period, bool useNaN) : this(source: source, period: period, multiplier: 2.0, useNaN: useNaN) { }
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update=false) {
var _mid = Mid.Add(TValue,update);
var _sd = this._sdev.Add(TValue, update);
var _upper = Upper.Add((TValue.t, _mid.v + _sd.v * _multiplier), update);
var _lower = Lower.Add((TValue.t, _mid.v - _sd.v * _multiplier), update);
double _pbdnd = TValue.v - _lower.v;
double _pbdvr = _upper.v - _lower.v;
PercentB.Add((TValue.t, _pbdnd/_pbdvr), update);
Zscore.Add((TValue.t, (TValue.v-_mid.v)/_sd.v), update);
Bandwidth.Add((TValue.t, _pbdvr / _mid.v), update);
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _pbdvr / _mid.v);
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); }
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() {
Mid.Clear();
_sdev.Clear();
Upper.Clear();
Lower.Clear();
}
}
+1 -4
View File
@@ -20,7 +20,7 @@ public class BIAS_Series : TSeries {
private readonly SMA_Series _sma;
//core constructors
public BIAS_Series(int period, bool useNaN) : base() {
public BIAS_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"BIAS({period})";
@@ -55,9 +55,6 @@ public class BIAS_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+86
View File
@@ -0,0 +1,86 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <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 : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TBars _data;
private readonly System.Collections.Generic.List<double> _tp = new();
//core constructors
public CCI_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"CCI({period})";
}
public CCI_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(data: _data);
}
public CCI_Series() : this(period: 2, useNaN: false) { }
public CCI_Series(int period) : this(period: period, useNaN: false) { }
public CCI_Series(TBars source) : this(source, period: 2, useNaN: false) { }
public CCI_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
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._period) { 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) ? 0 : (this._tp[this._tp.Count - 1] - _avgTp) / (0.015 * _avgDv);
var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _cci);
return base.Add(res, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_tp.Clear();
}
}
+2 -4
View File
@@ -27,7 +27,7 @@ public class CMO_Series : TSeries {
private double _plast_value, _last_value;
//core constructors
public CMO_Series(int period, bool useNaN) : base() {
public CMO_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"CMO({period})";
@@ -71,9 +71,7 @@ public class CMO_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+2 -5
View File
@@ -19,7 +19,7 @@ public class CUSUM_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public CUSUM_Series(int period, bool useNaN) : base() {
public CUSUM_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"CUSUM({period})";
@@ -35,7 +35,7 @@ public class CUSUM_Series : TSeries {
public CUSUM_Series(TBars source) : this(source.Close, 0, false) { }
public CUSUM_Series(TBars source, int period) : this(source.Close, period, false) { }
public CUSUM_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public CUSUM_Series(TSeries source) : this(source, 0, false) { }
public CUSUM_Series(TSeries source) : this(source, period: 0, useNaN: false) { }
public CUSUM_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
@@ -54,9 +54,6 @@ public class CUSUM_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -4
View File
@@ -22,7 +22,7 @@ public class DECAY_Series : TSeries {
private readonly double _dfactor;
//core constructors
public DECAY_Series(int period, bool exponential, bool useNaN) : base() {
public DECAY_Series(int period, bool exponential, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"DECAY({period})";
@@ -66,9 +66,6 @@ public class DECAY_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -5
View File
@@ -28,7 +28,7 @@ public class DEMA_Series : TSeries {
protected readonly TSeries _data;
//core constructor
public DEMA_Series(int period, bool useNaN, bool useSMA) : base() {
public DEMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
@@ -107,10 +107,6 @@ public class DEMA_Series : TSeries {
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return Add(_data.Last, update);
}
+2 -6
View File
@@ -13,14 +13,14 @@ DWMA: Double Weighted Moving Average
public class DWMA_Series : TSeries {
private readonly List<double> _buffer = new();
private List<double> _weights = new();
private List<double> _weights;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
protected int _len;
//core constructors
public DWMA_Series(int period, bool useNaN) : base() {
public DWMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"DWMA({period})";
@@ -91,10 +91,6 @@ public class DWMA_Series : TSeries {
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return Add(_data.Last, update);
}
+2 -5
View File
@@ -33,7 +33,7 @@ public class EMA_Series : TSeries {
//core constructors
public EMA_Series(int period, bool useNaN, bool useSMA) : base() {
public EMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
@@ -59,7 +59,7 @@ public class EMA_Series : TSeries {
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) {
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (update) {
_lastema = _oldema;
_sum = _oldsum;
@@ -102,9 +102,6 @@ public class EMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -4
View File
@@ -27,7 +27,7 @@ public class ENTROPY_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buff2 = new();
//core constructors
public ENTROPY_Series(int period, double logbase, bool useNaN) : base() {
public ENTROPY_Series(int period, double logbase, bool useNaN) {
_period = period;
_NaN = useNaN;
_logbase = logbase;
@@ -69,9 +69,6 @@ public class ENTROPY_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+2 -8
View File
@@ -12,13 +12,13 @@ FWMA: Fibonacci's Weighted Moving Average is similar to a Weighted Moving Averag
</summary> */
public class FWMA_Series : TSeries {
private readonly List<double> _buffer = new();
private List<double> _weights = new();
private List<double> _weights;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
protected int _len;
public FWMA_Series(int period, bool useNaN) : base() {
public FWMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"FWMA({period})";
@@ -65,12 +65,6 @@ public class FWMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
+10 -10
View File
@@ -24,11 +24,11 @@ public class HEMA_Series : TSeries {
private double _lasthema, _oldhema;
//core constructors
public HEMA_Series(int period, bool useNaN) : base() {
public HEMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"HEMA({period})";
CalculateK(_period, out _k1, out _k2, out _k3);
(_k1, _k2, _k3) = CalculateK(_period);
_len = 0;
_lastema1 = _oldema1 = _lastema2 = _oldema2 = _lasthema = _oldhema = 0;
}
@@ -62,7 +62,7 @@ public class HEMA_Series : TSeries {
double _ema1, _ema2, _hema;
if (_period == 0) {
_len++;
CalculateK(_len, out _k1, out _k2, out _k3);
(_k1, _k2, _k3) = CalculateK(_len);
}
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, double.NaN), update);
@@ -88,9 +88,6 @@ public class HEMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
@@ -108,9 +105,12 @@ public class HEMA_Series : TSeries {
_len = 0;
}
public static void CalculateK(int len, out double k1, out double k2, out double k3) {
k1 = 8 / (double)(len + 7);
k2 = 3 / (double)(len + 2);
k3 = 2 / Math.Sqrt(len + 3);
public static (double k1, double k2, double k3) CalculateK(int len) {
double k1 = 8 / (double)(len + 7);
double k2 = 3 / (double)(len + 2);
double k3 = 2 / Math.Sqrt(len + 3);
return (k1, k2, k3);
}
}
+1 -4
View File
@@ -25,7 +25,7 @@ public class HMA_Series : TSeries {
protected WMA_Series _wma1, _wma2, _wma3;
//core constructors
public HMA_Series(int period, bool useNaN) : base() {
public HMA_Series(int period, bool useNaN) {
_period = period;
_period2 = period /2;
_psqrt = (int)Math.Sqrt(period);
@@ -69,9 +69,6 @@ public class HMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+132
View File
@@ -0,0 +1,132 @@
namespace QuanTAlib;
using System;
using System.Linq;
/* <summary>
HWMA: Holt-Winter Moving Average
Indicator HWMA (Holt-Winter Moving Average) is a three-parameter moving
average by the Holt-Winter method; Holt-Winters Exponential Smoothing is
used for forecasting time series data that exhibits both a trend and a
seasonal variation.
Sources:
https://timeseriesreasoning.com/contents/holt-winters-exponential-smoothing/
https://www.mql5.com/en/code/20856
nA - smoothed series (from 0 to 1)
nB - assess the trend (from 0 to 1)
nC - assess seasonality (from 0 to 1)
Heuristic for determining alpha, beta, and gamma from period:
alpha = 2 / (1 + period)
beta = 1 / period
gamma = 1 / period
F[i] = (1-nA) * (F[i-1] + V[i-1] + 0.5 * A[i-1]) + nA * Price[i]
V[i] = (1-nB) * (V[i-1] + A[i-1]) + nB * (F[i] - F[i-1])
A[i] = (1-nC) * A[i-1] + nC * (V[i] - V[i-1])
HWMA[i] = F[i] + V[i] + 0.5 * A[i]
</summary> */
public class HWMA_Series : TSeries {
private int _len;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
double _nA, _nB, _nC;
double _pF, _pV, _pA;
double _ppF, _ppV, _ppA;
//core constructors
public HWMA_Series(double nA, double nB, double nC, bool useNaN) {
_period = (int)((2 - nA) / nA);
_nA = nA;
_nB = nB;
_nC = nC;
_NaN = useNaN;
Name = $"HWMA({_period})";
_len = 0;
}
public HWMA_Series(TSeries source, double nA, double nB, double nC, bool useNaN = false) : this(nA, nB, nC, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public HWMA_Series() : this(period: 0, useNaN: false) { }
public HWMA_Series(int period) : this(period, useNaN: false) { }
public HWMA_Series(int period, bool useNaN) : this(nA: 2 / (1 + (double)period), nB: 1 / (double)period, nC: 1 / (double)period, useNaN) {
_period = period;
}
public HWMA_Series(TBars source) : this(source.Close, period: 0, useNaN: false) { }
public HWMA_Series(TBars source, int period) : this(source.Close, period, false) { }
public HWMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public HWMA_Series(TSeries source, int period) : this(source, period, false) { }
public HWMA_Series(TSeries source, int period, bool useNaN) : this(source, nA: 2 / (1 + (double)period), nB: 1 / (double)period, nC: 1 / (double)period, 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);
}
double _F, _V, _A;
if (_len == 0) { _pF = TValue.v; _pA = _pV = 0; }
if (update) { _pF = _ppF; _pV = _ppV; _pA = _ppA; }
else {
_ppF = _pF;
_ppV = _pV;
_ppA = _pA;
_len++;
}
if (_period == 0) {
_nA = 2 / (1 + (double)_len);
_nB = 1 / (double)_len;
_nC = 1 / (double)_len;
}
if (_period == 1) {
_nA = 1;
_nB = 0;
_nC = 0;
}
_F = (1 - _nA) * (_pF + _pV + 0.5 * _pA) + _nA * TValue.v;
_V = (1 - _nB) * (_pV + _pA) + _nB * (_F - _pF);
_A = (1 - _nC) * _pA + _nC * (_V - _pV);
double _hwma = _F + _V + 0.5 * _A;
_pF = _F;
_pV = _V;
_pA = _A;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _hwma);
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;
}
}
+1 -4
View File
@@ -34,7 +34,7 @@ public class JMA_Series : TSeries {
private readonly int _voltyS, _voltyL;
//core constructors
public JMA_Series(int period, double phase, int vshort, int vlong, bool useNaN) : base() {
public JMA_Series(int period, double phase, int vshort, int vlong, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"JMA({period})";
@@ -147,9 +147,6 @@ public class JMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -8
View File
@@ -27,17 +27,15 @@ Remark:
public class KAMA_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
private double _lastkama, _lastlastkama;
private int _len;
private readonly double _scFast, _scSlow;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public KAMA_Series(int period, int fast, int slow, bool useNaN) : base() {
public KAMA_Series(int period, int fast, int slow, bool useNaN) {
_period = period;
_NaN = useNaN;
_len = 0;
_scFast = 2.0 / (((period < fast) ? period : fast) + 1);
_scSlow = 2.0 / (slow + 1);
_lastkama = _lastlastkama = 0;
@@ -81,7 +79,6 @@ public class KAMA_Series : TSeries {
double _sc = (_er * (_scFast - _scSlow)) + _scSlow;
_kama = (_lastkama + (_sc * _sc * (TValue.v - _lastkama)));
}
_len++;
_lastkama = _kama;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _kama);
return base.Add(res, update);
@@ -92,9 +89,6 @@ public class KAMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
@@ -108,7 +102,6 @@ public class KAMA_Series : TSeries {
//reset calculation
public override void Reset() {
_buffer.Clear();
_len = 0;
_lastkama = _lastlastkama = 0;
}
}
+1 -4
View File
@@ -32,7 +32,7 @@ public class KURTOSIS_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
//core constructors
public KURTOSIS_Series(int period, bool useNaN) : base() {
public KURTOSIS_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"KURTOSIS({period})";
@@ -79,9 +79,6 @@ public class KURTOSIS_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+78
View File
@@ -0,0 +1,78 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
MACD: Moving Average Convergence/Divergence
Moving average convergence divergence (MACD) is a trend-following momentum
indicator that shows the relationship between two moving averages of a series.
The MACD is calculated by subtracting the 26-period exponential moving average (EMA)
from the 12-period EMA. MACD Signal is 9-day EMA of MACD.
</summary> */
public class MACD_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _slow, _fast, _signal;
protected readonly bool _NaN;
protected readonly TSeries _data;
private readonly EMA_Series _TSlow;
private readonly EMA_Series _TFast;
public EMA_Series Signal { get; }
//core constructors
public MACD_Series(int slow = 26, int fast = 12, int signal = 9, bool useNaN = false) {
_slow = slow;
_fast = fast;
_signal = signal;
_NaN = useNaN;
Name = $"MACD({slow},{fast},{signal})";
_TSlow = new(slow, useNaN:false, useSMA:true);
_TFast = new(fast, useNaN: false, useSMA: true);
Signal = new(signal, useNaN: false, useSMA: true);
}
public MACD_Series(TSeries source, int slow, int fast, int signal, bool useNaN) : this(slow, fast, signal, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public MACD_Series(TSeries source) : this(source:source, slow:26, fast:12, signal:9 , useNaN:false) { }
public MACD_Series(TSeries source, int slow, int fast, int signal) : this(source: source, slow: slow, fast:fast, signal:signal, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN), update);
}
var _sslow = _TSlow.Add(TValue,update);
var _sfast = _TFast.Add(TValue, update);
Signal.Add((TValue.t, _sfast.v-_sslow.v));
var res = (TValue.t, Count < _fast - 1 && _NaN ? double.NaN : _sfast.v-_sslow.v);
return base.Add(res, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TValue: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TValue: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
+1 -4
View File
@@ -24,7 +24,7 @@ public class MAD_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public MAD_Series(int period, bool useNaN) : base() {
public MAD_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MAD({period})";
@@ -62,9 +62,6 @@ public class MAD_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
@@ -1,49 +1,57 @@
namespace QuanTAlib;
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
MAE: Mean Absolute Error
Defined as a Mean (Average) of the absolute difference between actual and estimated values.
MAE = (1/n) * Σ|y_i - MA_i|
Sources:
https://en.wikipedia.org/wiki/Mean_absolute_error
</summary> */
public class xMA_Series : TSeries {
public class MAE_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public xMA_Series(int period, bool useNaN) : base() {
public MAE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"xMA({period})";
Name = $"MSE({period})";
}
public xMA_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
public MAE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public xMA_Series() : this(period: 0, useNaN: false) { }
public xMA_Series(int period) : this(period: period, useNaN: false) { }
public xMA_Series(TBars source) : this(source.Close, 0, false) { }
public xMA_Series(TBars source, int period) : this(source.Close, period, false) { }
public xMA_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public xMA_Series(TSeries source) : this(source, 0, false) { }
public xMA_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
public MAE_Series() : this(period: 0, useNaN: false) { }
public MAE_Series(int period) : this(period: period, useNaN: false) { }
public MAE_Series(TBars source) : this(source.Close, 0, false) { }
public MAE_Series(TBars source, int period) : this(source.Close, period, false) { }
public MAE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public MAE_Series(TSeries source) : this(source, 0, false) { }
public MAE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) {
return base.Add((TValue.t, Double.NaN), update);
}
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _xma = 0;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _xma);
double _sma = _buffer.Average();
double _mae = 0;
for (int i = 0; i < _buffer.Count; i++) { _mae += Math.Abs(_buffer[i] - _sma); }
_mae /= this._buffer.Count;
var res = (TValue.t, Count < _period - 1 && _NaN ? double.NaN : _mae);
return base.Add(res, update);
}
@@ -52,9 +60,6 @@ public class xMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+189
View File
@@ -0,0 +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;
}
}
+1 -4
View File
@@ -27,7 +27,7 @@ public class MAPE_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public MAPE_Series(int period, bool useNaN) : base() {
public MAPE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MAPE({period})";
@@ -68,9 +68,6 @@ public class MAPE_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -4
View File
@@ -17,7 +17,7 @@ public class MAX_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public MAX_Series(int period, bool useNaN) : base() {
public MAX_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MAX({period})";
@@ -51,9 +51,6 @@ public class MAX_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -4
View File
@@ -30,7 +30,7 @@ public class MEDIAN_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public MEDIAN_Series(int period, bool useNaN) : base() {
public MEDIAN_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MEDIAN({period})";
@@ -69,9 +69,6 @@ public class MEDIAN_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -4
View File
@@ -20,7 +20,7 @@ public class MIDPOINT_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public MIDPOINT_Series(int period, bool useNaN) : base() {
public MIDPOINT_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MIDPOINT({period})";
@@ -55,9 +55,6 @@ public class MIDPOINT_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+65
View File
@@ -0,0 +1,65 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
MIDPRICE: Midpoint price (highhest high + lowest low)/2 in the given period in the series.
If period = 0 => period = full length of the series
</summary> */
public class MIDPRICE_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TBars _data;
private readonly System.Collections.Generic.List<double> _bufferhi = new();
private readonly System.Collections.Generic.List<double> _bufferlo = new();
//core constructors
public MIDPRICE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MIDPRICE({period})";
}
public MIDPRICE_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(data: _data);
}
public MIDPRICE_Series() : this(period: 2, useNaN: false) { }
public MIDPRICE_Series(int period) : this(period: period, useNaN: false) { }
public MIDPRICE_Series(TBars source) : this(source, period: 2, useNaN: false) { }
public MIDPRICE_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
BufferTrim(_bufferhi, TBar.h, _period, update);
BufferTrim(_bufferlo, TBar.l, _period, update);
double _mid = (_bufferhi.Max() + _bufferlo.Min()) * 0.5;
var res = (TBar.t, Count < _period - 1 && _NaN ? double.NaN : _mid);
return base.Add(res, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_bufferhi.Clear();
_bufferlo.Clear();
}
}
+1 -4
View File
@@ -17,7 +17,7 @@ public class MIN_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public MIN_Series(int period, bool useNaN) : base() {
public MIN_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MAX({period})";
@@ -51,9 +51,6 @@ public class MIN_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -4
View File
@@ -20,7 +20,7 @@ public class MSE_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public MSE_Series(int period, bool useNaN) : base() {
public MSE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"MSE({period})";
@@ -59,9 +59,6 @@ public class MSE_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+96
View File
@@ -0,0 +1,96 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
using System.Linq;
/* <summary>
OBV: On-Balance Volume
On-balance volume (OBV) is a technical trading momentum indicator that uses volume flow to predict
changes in stock price. Joseph Granville first developed the OBV metric in the 1963 book
Granville's New Key to Stock Market Profits.
| +volume; if close > close[previous]
OBV = OBV[previous] + | 0; if close = close[previous]
| -volume; if close < close[previous]
Sources:
https://www.investopedia.com/terms/o/onbalancevolume.asp
https://www.tradingview.com/wiki/On_Balance_Volume_(OBV)
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/on-balance-volume-obv/
https://www.motivewave.com/studies/on_balance_volume.htm
Note:
There is no consensus on what is the first OBV value in the series:
- TA-LIB uses the first volume: OBV[0] = volume[0]
- Skender stock library uses 0: OBV[0] = 0
</summary> */
public class OBV_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TBars _data;
private double _lastobv, _lastlastobv;
private double _lastclose, _lastlastclose;
//core constructors
public OBV_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"OBV({period})";
this._lastobv = this._lastlastobv = 0;
this._lastclose = this._lastlastclose = 0;
}
public OBV_Series(TBars source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(data: _data);
}
public OBV_Series() : this(period: 2, useNaN: false) { }
public OBV_Series(int period) : this(period: period, useNaN: false) { }
public OBV_Series(TBars source) : this(source, period: 2, useNaN: false) { }
public OBV_Series(TBars source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) {
this._lastobv = this._lastlastobv;
this._lastclose = this._lastlastclose;
}
double _obv = this._lastobv;
if (TBar.c > this._lastclose) { _obv += TBar.v; }
if (TBar.c < this._lastclose) { _obv -= TBar.v; }
this._lastlastobv = this._lastobv;
this._lastobv = _obv;
this._lastlastclose = this._lastclose;
this._lastclose = TBar.c;
var res = (TBar.t, (this.Count < this._period && this._NaN) ? double.NaN : _obv);
return base.Add(res, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
this._lastobv = this._lastlastobv = 0;
this._lastclose = this._lastlastclose = 0;
}
}
+2 -5
View File
@@ -31,7 +31,7 @@ public class RMA_Series : TSeries {
protected readonly TSeries _data;
//core constructor
public RMA_Series(int period, bool useNaN, bool useSMA) : base() {
public RMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
@@ -57,7 +57,7 @@ public class RMA_Series : TSeries {
}
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) {
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (update) {
_lastrma = _oldrma;
_sum = _oldsum;
@@ -98,9 +98,6 @@ public class RMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -4
View File
@@ -26,7 +26,7 @@ public class RSI_Series : TSeries {
private int i;
//core constructors
public RSI_Series(int period, bool useNaN) : base() {
public RSI_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"RSI({period})";
@@ -103,9 +103,6 @@ public class RSI_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -4
View File
@@ -25,7 +25,7 @@ public class SDEV_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public SDEV_Series(int period, bool useNaN) : base() {
public SDEV_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SDEV({period})";
@@ -65,9 +65,6 @@ public class SDEV_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+122
View File
@@ -0,0 +1,122 @@
using System.Linq;
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <summary>
SLOPE: Slope of linear regression (using Least Square Method)
Linear Regression provides a slope of a straight line that is the best approximation of the given set of data.
The method of least squares is a standard approach in linear regression analysis to approximate the solution
by minimizing the sum of the squares of the residuals made in the results of each individual equation.
Additional outputs provided by LINREG:
.Intercept - y-intercept point of the best fit line
.RSquared - R-Squared (R²), Coefficient of Determination
.StdDev - Standard Deviation of data over given periods
y = Slope * x + Intercept
Sources:
https://en.wikipedia.org/wiki/Least_squares
</summary> */
public class SLOPE_Series : TSeries {
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
private readonly TSeries p_Intercept = new();
private readonly TSeries p_RSquared = new();
private readonly TSeries p_StdDev = new();
private readonly System.Collections.Generic.List<double> _buffer = new();
public TSeries Intercept => p_Intercept;
public TSeries RSquared => p_RSquared;
public TSeries StdDev => p_StdDev;
//core constructors
public SLOPE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SLOPE({period})";
}
public SLOPE_Series(TSeries source, int period, bool useNaN) : this(period, useNaN) {
_data = source;
Name = Name.Substring(0, Name.IndexOf(")")) + $", {(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_data.Pub += Sub;
Add(_data);
}
public SLOPE_Series() : this(period: 0, useNaN: false) { }
public SLOPE_Series(int period) : this(period: period, useNaN: false) { }
public SLOPE_Series(TBars source) : this(source.Close, 0, false) { }
public SLOPE_Series(TBars source, int period) : this(source.Close, period, false) { }
public SLOPE_Series(TBars source, int period, bool useNaN) : this(source.Close, period, useNaN) { }
public SLOPE_Series(TSeries source) : this(source, 0, false) { }
public SLOPE_Series(TSeries source, int period) : this(source: source, period: period, useNaN: false) { }
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
int _len = this._buffer.Count;
// get averages for period
double sumX = 0;
double sumY = 0;
for (int p = 0; p < _len; p++) {
sumX += this.Count - _len + 2 + p;
sumY += _buffer[p];
}
double avgX = sumX / _len;
double avgY = sumY / _len;
// least squares method
double sumSqX = 0;
double sumSqY = 0;
double sumSqXY = 0;
for (int p = 0; p < _len; p++) {
double devX = this.Count - _len + 2 + p - avgX;
double devY = _buffer[p] - avgY;
sumSqX += devX * devX;
sumSqY += devY * devY;
sumSqXY += devX * devY;
}
double _slope = sumSqXY / sumSqX;
double _intercept = avgY - (_slope * avgX);
// calculate Standard Deviation and R-Squared
double stdDevX = Math.Sqrt(sumSqX / _len);
double stdDevY = Math.Sqrt(sumSqY / _len);
double _StdDev = stdDevY;
double arrr = (stdDevX * stdDevY != 0) ? sumSqXY / (stdDevX * stdDevY) / _len : 0;
double _RSquared = arrr * arrr;
var ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _intercept);
p_Intercept.Add(ret, update);
ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _StdDev);
p_StdDev.Add(ret, update);
ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _RSquared);
p_RSquared.Add(ret, update);
ret = (TValue.t, this.Count < this._period - 1 && this._NaN ? double.NaN : _slope);
return base.Add(ret, update);
}
public override (DateTime t, double v) Add(TSeries data) {
if (data == null) { return (DateTime.Today, Double.NaN); }
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
//reset calculation
public override void Reset() {
_buffer.Clear();
}
}
+1 -6
View File
@@ -20,7 +20,7 @@ public class SMAPE_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public SMAPE_Series(int period, bool useNaN) : base() {
public SMAPE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SMAPE({period})";
@@ -45,8 +45,6 @@ public class SMAPE_Series : TSeries {
BufferTrim(buffer:_buffer, value:TValue.v, period:_period, update: update);
double _sma = _buffer.Average();
double _smape = 0;
for (int i = 0; i < _buffer.Count; i++) { _smape += Math.Abs(_buffer[i] - _sma) / (Math.Abs(_buffer[i]) + Math.Abs(_sma)); }
_smape /= this._buffer.Count;
@@ -60,9 +58,6 @@ public class SMAPE_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+2 -5
View File
@@ -25,7 +25,7 @@ public class SMA_Series : TSeries {
protected readonly bool _NaN;
//core constructor
public SMA_Series(int period, bool useNaN) : base() {
public SMA_Series(int period, bool useNaN) {
_period = Math.Max(0, period);
_NaN = useNaN;
Name = $"SMA({period})";
@@ -47,7 +47,7 @@ public class SMA_Series : TSeries {
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) {
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (double.IsNaN(TValue.v)) { return (TValue.t, double.NaN);
} else {
if (update && _buffer.Count > 0) {
@@ -77,9 +77,6 @@ public class SMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -4
View File
@@ -27,7 +27,7 @@ public class SMMA_Series : TSeries {
private double _lastsmma, _lastlastsmma;
//core constructors
public SMMA_Series(int period, bool useNaN) : base() {
public SMMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SMMA({period})";
@@ -75,9 +75,6 @@ public class SMMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -4
View File
@@ -25,7 +25,7 @@ public class SSDEV_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public SSDEV_Series(int period, bool useNaN) : base() {
public SSDEV_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SSDEV({period})";
@@ -65,9 +65,6 @@ public class SSDEV_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -4
View File
@@ -25,7 +25,7 @@ public class SVAR_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public SVAR_Series(int period, bool useNaN) : base() {
public SVAR_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"SVAR({period})";
@@ -64,9 +64,6 @@ public class SVAR_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -4
View File
@@ -31,7 +31,7 @@ public class T3_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public T3_Series(int period, double vfactor, bool useSMA, bool useNaN) : base() {
public T3_Series(int period, double vfactor, bool useSMA, bool useNaN) {
_period = period;
_len = 0;
_NaN = useNaN;
@@ -137,9 +137,6 @@ public class T3_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+19 -7
View File
@@ -84,16 +84,16 @@ public class TBars : System.Collections.Generic.List<(DateTime t, double o, doub
};
}
public virtual (DateTime t, double o, double h, double l, double c, double v) Add((double o, double h, double l, double c, double v) p, bool update = false) =>
public virtual (DateTime t, double v) Add((double o, double h, double l, double c, double v) p, bool update = false) =>
Add((t: (this.Count == 0) ? DateTime.Today : this[^1].t.AddDays(1),p.o,p.h,p.l,p.c,p.v),update);
public virtual (DateTime t, double o, double h, double l, double c, double v) Add(double o, double h, double l, double c, double v, bool update = false) =>
public virtual (DateTime t, double v) Add(double o, double h, double l, double c, double v, bool update = false) =>
Add((o,h,l,c,v),update);
public virtual (DateTime t, double o, double h, double l, double c, double v) Add(DateTime t, double o, double h, double l, double c, double v, bool update = false) =>
public virtual (DateTime t, double v) Add(DateTime t, double o, double h, double l, double c, double v, bool update = false) =>
this.Add((t, o, h, l, c, v), update);
public virtual (DateTime t, double o, double h, double l, double c, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
public virtual (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) { this[^1] = TBar; } else { base.Add(TBar); }
_open.Add((TBar.t, TBar.o), update);
@@ -109,8 +109,8 @@ public class TBars : System.Collections.Generic.List<(DateTime t, double o, doub
_hlcc4.Add((TBar.t, (TBar.h + TBar.l + TBar.c + TBar.c) * 0.25), update);
this.OnEvent(update);
return TBar;
}
return (TBar.t, (TBar.o + TBar.h + TBar.l + TBar.c) * 0.25);
}
public delegate void NewDataEventHandler(object source, TSeriesEventArgs args);
public event NewDataEventHandler Pub;
@@ -120,7 +120,19 @@ public class TBars : System.Collections.Generic.List<(DateTime t, double o, doub
public void Sub(object source, TSeriesEventArgs e) { TBars ss = (TBars)source; if (ss.Count > 1) {
for (int i = 0; i < ss.Count; i++) { this.Add(ss[i]); }
} else {
this.Add(ss[ss.Count - 1], e.update);
this.Add(ss[^1], e.update);
}
}
/// common helpers
public static void BufferTrim(System.Collections.Generic.List<double> buffer, double value, int period, bool update) {
if (!update) {
buffer.Add(value);
if (buffer.Count > period && period > 0) { buffer.RemoveAt(0); }
return;
}
buffer[^1] = value;
}
public virtual void Reset() {
}
}
+1 -4
View File
@@ -29,7 +29,7 @@ public class TEMA_Series : TSeries {
protected readonly TSeries _data;
//core constructor
public TEMA_Series(int period, bool useNaN, bool useSMA) : base() {
public TEMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
@@ -102,9 +102,6 @@ public class TEMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+2 -5
View File
@@ -17,13 +17,13 @@ Remark:
public class TRIMA_Series : TSeries {
private readonly int _p1a, _p1b;
private SMA_Series sma, trima;
private readonly SMA_Series sma, trima;
protected readonly int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
//core constructors
public TRIMA_Series(int period, bool useNaN) : base() {
public TRIMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"xMA({period})";
@@ -66,9 +66,6 @@ public class TRIMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+8 -9
View File
@@ -21,7 +21,7 @@ public class TRIX_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer3 = new();
private double _lastema1, _lastema2, _lastema3;
private double _llastema1, _llastema2, _llastema3;
private int _len;
private readonly bool _useSMA;
protected readonly int _period;
protected readonly bool _NaN;
@@ -29,12 +29,13 @@ public class TRIX_Series : TSeries {
//core constructors
public TRIX_Series(int period, bool useNaN, bool useSMA) : base() {
public TRIX_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
_useSMA = useSMA;
Name = $"TRIX({period})";
_k = 2.0 / (_period + 1);
_len = 0;
_lastema1 = _llastema1 = _lastema2 = _llastema2 = _lastema3 = _llastema3 = 0;
}
public TRIX_Series(TSeries source, int period, bool useNaN, bool useSMA) : this(period, useNaN, useSMA) {
@@ -54,13 +55,14 @@ public class TRIX_Series : TSeries {
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) {
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 (this.Count == 0) { _lastema1 = _lastema2 = _lastema3 = TValue.v; }
if (_len == 0) { _lastema1 = _lastema2 = _lastema3 = TValue.v; }
if (update) { _lastema1 = _llastema1; _lastema2 = _llastema2; _lastema3 = _llastema3; }
else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; }
else { _llastema1 = _lastema1; _llastema2 = _lastema2; _llastema3 = _lastema3; _len++;
}
double _ema1, _ema2, _ema3;
if ((this.Count < _period) && _useSMA) {
@@ -99,9 +101,6 @@ public class TRIX_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
@@ -114,6 +113,6 @@ public class TRIX_Series : TSeries {
//reset calculation
public override void Reset() {
_len = 0;
}
}
+79
View File
@@ -0,0 +1,79 @@
namespace QuanTAlib;
using System;
using System.Collections.Generic;
/* <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 : TSeries {
protected readonly TBars _data;
private double _cm1, _cm1_o;
//core constructors
public TR_Series() {
Name = $"TR()";
_cm1 = _cm1_o = double.NaN;
}
public TR_Series(TBars source) {
_data = source;
Name = $"TR({(string.IsNullOrEmpty(_data.Name) ? "data" : _data.Name)})";
_cm1 = _cm1_o = double.NaN;
_data.Pub += Sub;
Add(data: _data);
}
//////////////////
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) {
_cm1 = _cm1_o;
}
else {
_cm1_o = _cm1;
}
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);
_cm1 = TBar.c;
var ret = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
return base.Add(ret, update);
}
public new void Add(TBars data) {
foreach (var item in data) { Add(item, false); }
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TBar: _data.Last, update: update);
}
public (DateTime t, double v) Add() {
return Add(TBar: _data.Last, update: false);
}
private new void Sub(object source, TSeriesEventArgs e) {
Add(TBar: _data.Last, update: e.update);
}
//reset calculation
public override void Reset() {
_cm1 = _cm1_o = double.NaN;
}
}
+22 -5
View File
@@ -22,7 +22,7 @@ public class TSeriesEventArgs : EventArgs {
public class TSeries : List<(DateTime t, double v)> {
public List<DateTime> t => this.Select(item => item.t).ToList();
public List<double> v => this.Select(item => item.v).ToList();
public (DateTime t, double v) Last => this[^1];
public (DateTime t, double v) Last => this[this.Count - 1];
public int Length => Count;
public string Name { get; set; }
@@ -35,13 +35,13 @@ public class TSeries : List<(DateTime t, double v)> {
}
public virtual (DateTime t, double v) Add(double v, bool update = false) {
var Value = (t: Count == 0 ? DateTime.Today : this[^1].t.AddDays(1), v);
var Value = (t: Count == 0 ? DateTime.Today : this[this.Count-1].t.AddDays(1), v);
return Add(Value, update);
}
public virtual (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
if (update) {
this[^1] = TValue;
this[this.Count-1] = TValue;
}
else {
base.Add(TValue);
@@ -51,15 +51,32 @@ public class TSeries : List<(DateTime t, double v)> {
return TValue;
}
public virtual (DateTime t, double v) Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update = false) {
if (update) {
this[this.Count - 1] = (TBar.t, TBar.c);
}
else {
base.Add((TBar.t, TBar.c));
}
OnEvent(update);
return (TBar.t, TBar.c);
}
public virtual (DateTime t, double v) Add(TSeries data) {
foreach (var item in data) { Add(item, false); }
foreach (var item in data) { Add(item); }
return data.Last;
}
public virtual (DateTime t, double v) Add(TBars data) {
foreach (var item in data) { Add(item.c, false); }
return (data.Last.t, data.Last.c);
}
public void Sub(object source, TSeriesEventArgs e) {
var data = (TSeries) source;
if (data == null) { return; }
foreach (var item in data) { Add(item, update: false); }
foreach (var item in data) { Add(item); }
}
public delegate void NewEventHandler(object source, TSeriesEventArgs args);
+1 -4
View File
@@ -25,7 +25,7 @@ public class VAR_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public VAR_Series(int period, bool useNaN) : base() {
public VAR_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"VAR({period})";
@@ -64,9 +64,6 @@ public class VAR_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -4
View File
@@ -22,7 +22,7 @@ public class WMAPE_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public WMAPE_Series(int period, bool useNaN) : base() {
public WMAPE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"WMAPE({period})";
@@ -65,9 +65,6 @@ public class WMAPE_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+2 -5
View File
@@ -19,7 +19,7 @@ Sources:
public class WMA_Series : TSeries {
private readonly System.Collections.Generic.List<double> _buffer = new();
private System.Collections.Generic.List<double> _weights = new();
private System.Collections.Generic.List<double> _weights;
protected int _period;
protected readonly bool _NaN;
protected readonly TSeries _data;
@@ -30,7 +30,7 @@ public class WMA_Series : TSeries {
}
//core constructors
public WMA_Series(int period, bool useNaN) : base() {
public WMA_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"WMA({period})";
@@ -76,9 +76,6 @@ public class WMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+3 -5
View File
@@ -30,7 +30,7 @@ public class ZLEMA_Series : TSeries {
private readonly EMA_Series _ema;
//core constructor
public ZLEMA_Series(int period, bool useNaN, bool useSMA) : base() {
public ZLEMA_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
Name = $"ZLEMA({period})";
@@ -54,7 +54,7 @@ public class ZLEMA_Series : TSeries {
}
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) {
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
int _lag;
if (_period == 0) {
@@ -76,9 +76,7 @@ public class ZLEMA_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+2 -5
View File
@@ -26,7 +26,7 @@ public class ZL_Series: TSeries {
private readonly EMA_Series _ema;
//core constructor
public ZL_Series(int period, bool useNaN, bool useSMA) : base() {
public ZL_Series(int period, bool useNaN, bool useSMA) {
_period = period;
_NaN = useNaN;
Name = $"ZL({period})";
@@ -50,7 +50,7 @@ public class ZL_Series: TSeries {
}
// core Add() algo
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update) {
public override (DateTime t, double v) Add((DateTime t, double v) TValue, bool update = false) {
BufferTrim(buffer: _buffer, value: TValue.v, period: _period, update: update);
int _lag;
if (_period == 0) {
@@ -72,9 +72,6 @@ public class ZL_Series: TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+1 -4
View File
@@ -31,7 +31,7 @@ public class ZSCORE_Series : TSeries {
protected readonly TSeries _data;
//core constructors
public ZSCORE_Series(int period, bool useNaN) : base() {
public ZSCORE_Series(int period, bool useNaN) {
_period = period;
_NaN = useNaN;
Name = $"ZSCORE({period})";
@@ -71,9 +71,6 @@ public class ZSCORE_Series : TSeries {
foreach (var item in data) { Add(item, false); }
return _data.Last;
}
public new (DateTime t, double v) Add((DateTime t, double v) TValue) {
return Add(TValue, false);
}
public (DateTime t, double v) Add(bool update) {
return this.Add(TValue: _data.Last, update: update);
}
+5 -4
View File
@@ -39,7 +39,7 @@ public class MovingAverageSlope_chart : Indicator {
private bool LongTrades = true;
[InputParameter("Short trades", 8)]
private bool ShortTrades = false;
private bool ShortTrades;
#endregion Parameters
@@ -48,7 +48,7 @@ public class MovingAverageSlope_chart : Indicator {
///////
private TSeries MA1, MA2;
private LINREG_Series sMA1, sMA2;
private SLOPE_Series sMA1, sMA2;
private CROSS_Series sig1, sig2;
private bool inLong, inShort;
@@ -276,11 +276,12 @@ public class MovingAverageSlope_chart : Indicator {
Graphics graphics = args.Graphics;
var mainWindow = this.CurrentChart.MainWindow;
int leftIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left));
int rightIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right)));
int rightIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right)));
/*
int historycount = HistoricalData.Count;
int ymax = mainWindow.ClientRectangle.Height;
/*
for (int i = leftIndex; i <= rightIndex; i++) {
int xi = (int)Math.Round(mainWindow.CoordinatesConverter.GetChartX(Time(Count - 1 - i)));
int width = this.CurrentChart.BarsWidth;
+5 -3
View File
@@ -24,7 +24,7 @@ public class JMA_chart : Indicator {
private int Vlong = 65;
[InputParameter("Phase", 4, -100, 100, 1, 2)]
private double Jphase = 0.0;
private double Jphase;
#endregion Parameters
@@ -38,7 +38,7 @@ public class JMA_chart : Indicator {
protected int firstOnScreenBarIndex, lastOnScreenBarIndex;
protected HistoricalData History;
protected int HistPeriod;
public JMA_chart() :base() {
public JMA_chart() {
Name = "JMA - Jurik Moving Avg";
Description = "Jurik Moving Average description";
AddLineSeries(lineName: "JMA", lineColor: Color.Yellow, lineWidth: 3,lineStyle: LineStyle.Solid);
@@ -80,8 +80,10 @@ public class JMA_chart : Indicator {
}
public override void OnPaintChart(PaintChartEventArgs args) {
base.OnPaintChart(args);
if (this.CurrentChart == null)
if (this.CurrentChart == null) {
return;
}
graphics = args.Graphics;
mainWindow = this.CurrentChart.MainWindow;
+1 -26
View File
@@ -30,7 +30,7 @@ public class TrailingStop_chart : Indicator {
///////
public TrailingStop_chart() :base() {
public TrailingStop_chart() {
Name = $"ATR Trailing Stop";
AddLineSeries(lineName: "TrailingATR Long", lineColor: Color.Yellow, lineWidth: 1,lineStyle: LineStyle.Dot);
AddLineSeries(lineName: "Ratchet Long", lineColor: Color.Yellow, lineWidth: 3, lineStyle: LineStyle.Solid);
@@ -91,30 +91,5 @@ public class TrailingStop_chart : Indicator {
this.SetValue(_tslineS, lineIndex: 2);
this.SetValue(_ratchetS, lineIndex: 3);
}
public override void OnPaintChart(PaintChartEventArgs args) {
base.OnPaintChart(args);
if (this.CurrentChart == null) { return; }
Graphics graphics = args.Graphics;
var mainWindow = this.CurrentChart.MainWindow;
int leftIndex = (int)mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Left));
int rightIndex = (int)Math.Ceiling(mainWindow.CoordinatesConverter.GetBarIndex(mainWindow.CoordinatesConverter.GetTime(mainWindow.ClientRectangle.Right)));
int historycount = HistoricalData.Count;
int ymax = mainWindow.ClientRectangle.Height;
/*
for (int i = leftIndex; i <= rightIndex; i++) {
int xi = (int)Math.Round(mainWindow.CoordinatesConverter.GetChartX(Time(Count - 1 - i)));
int width = this.CurrentChart.BarsWidth;
int height = (int)((equity[i+historycount].v) *proportion);
Brush bb = Brushes.DarkSlateGray;
bb = (overunder[i+historycount].v>0 && LongTrades)? Brushes.Green : bb;
bb = (overunder[i + historycount].v < 0 && ShortTrades) ? Brushes.Red : bb;
graphics.FillRectangle(bb, xi, ymax - height, width, height);
}
*/
}
}
+7 -25
View File
@@ -14,16 +14,16 @@ namespace SimpleMACross {
public Account CurrentAccount { get; set; }
[InputParameter("Fast MA", 2, minimum: 1, maximum: 100, increment: 1, decimalPlaces: 0)]
public int FastMA = 5;
private int FastMA = 5;
[InputParameter("Slow MA", 3, minimum: 1, maximum: 100, increment: 1, decimalPlaces: 0)]
public int SlowMA = 10;
private int SlowMA = 10;
[InputParameter("Quantity", 4, 0.1, 99999, 0.1, 2)]
public double Quantity = 1.0;
private double Quantity = 1.0;
[InputParameter("Period", 5)]
public Period period = Period.MIN1;
private Period period = Period.MIN1;
public override string[] MonitoringConnectionsIds => new string[] { this.CurrentSymbol?.ConnectionId, this.CurrentAccount?.ConnectionId };
@@ -31,9 +31,8 @@ namespace SimpleMACross {
private DateTime prev_time;
private readonly TBars bars = new();
public SimpleMACross1()
: base() {
this.Name = "Miha MA Cross strategy 3";
public SimpleMACross1() {
this.Name = "MA Cross strategy 3";
this.Description = "Raw strategy without any additional functional";
}
@@ -73,24 +72,7 @@ namespace SimpleMACross {
// An example of adding custom strategy metrics:
result.Add("Bars processed", this.bars.Count.ToString());
/*
result.Add("Trades [#]", "0");
result.Add("Long trades [#]", this.longPositionsCount.ToString());
result.Add("Short trades [#]", this.shortPositionsCount.ToString());
result.Add("Profitable trades [#]", "0");
result.Add("Win Rate [%]", "0");
result.Add("Best Trade [%]", "0");
result.Add("Worst Trade[%]", "0");
result.Add("Avg Winning Trade [%]", "0");
result.Add("Avg Losing Trade [%]", "0");
result.Add("Profit Factor", "0");
result.Add("Sharpe Ratio", "0");
result.Add("Sortino Ratio", "0");
result.Add("Omega Ratio", "0");
result.Add("Calmar Ratio", "0");
result.Add("Beta", "0");
result.Add("Alpha", "0");
*/
return result;
}
-3
View File
@@ -34,9 +34,6 @@
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<PlatformTarget>anycpu</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<AdditionalFiles Include="..\.sonarlint\mihakralj_quantalib\CSharp\SonarLint.xml" Link="SonarLint.xml" />
</ItemGroup>
<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
<Copy SourceFiles=".\bin\$(Configuration)\QuanTAlib_Strategies.dll" DestinationFolder="\Quantower\Settings\Scripts\Strategies\QuanTAlib" />
</Target>
+2
View File
@@ -26,6 +26,8 @@ public class Indicators
typeof(T3_Series),
typeof(KAMA_Series),
typeof(TRIMA_Series),
typeof(MAMA_Series),
typeof(HWMA_Series),
};
[Theory]
+4 -2
View File
@@ -7,7 +7,7 @@ namespace Basics;
#nullable disable
public class Oscillators
{
private static Type[] maSeriesTypes = new Type[]
private static Type[] maSeriesTypes = new[]
{
typeof(BIAS_Series),
typeof(MAX_Series),
@@ -19,7 +19,8 @@ public class Oscillators
typeof(KURTOSIS_Series),
typeof(MAD_Series),
typeof(MAPE_Series),
typeof(MSE_Series),
typeof(MAE_Series),
typeof(MSE_Series),
typeof(SDEV_Series),
typeof(SMAPE_Series),
typeof(WMAPE_Series),
@@ -31,6 +32,7 @@ public class Oscillators
typeof(CMO_Series),
typeof(RSI_Series),
typeof(TRIX_Series),
typeof(BBANDS_Series),
};
[Theory]
+96
View File
@@ -0,0 +1,96 @@
using Xunit;
using System;
using System.Runtime.InteropServices;
using QuanTAlib;
namespace Basics;
#nullable disable
public class TBars
{
private static Type[] maSeriesTypes = new Type[]
{
typeof(ATR_Series),
typeof(ATRP_Series),
typeof(TR_Series),
typeof(ADL_Series),
typeof(CCI_Series),
typeof(OBV_Series),
typeof(ADOSC_Series),
typeof(MIDPRICE_Series),
};
[Theory]
[MemberData(nameof(MASeriesData))]
public void Name_exists(Type classType)
{
GBM_Feed data = new(10);
var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
Assert.NotEmpty(MA_Series.Name);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Series_Length(Type classType)
{
GBM_Feed data = new(1000);
var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
Assert.Equal(1000, MA_Series.Count);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Return_data(Type classType)
{
GBM_Feed data = new(10);
var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
var result = MA_Series.Add((DateTime.Today, 1,2,3,4,5));
Assert.Equal(result.v, MA_Series.Last.v);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Update(Type classType)
{
GBM_Feed data = new(10);
var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
var pre_update = MA_Series.Last;
var pre_data = data.Last;
data.Add((DateTime.Today, 1, 2, 3, 4, 5), true);
data.Add(pre_data, true);
Assert.Equal(pre_update.v, MA_Series.Last.v);
Assert.Equal(data.Count, MA_Series.Count);
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Reset(Type classType)
{
GBM_Feed data = new(10);
var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
MA_Series.Reset();
data.Add();
Assert.False(double.IsNaN(MA_Series.Last.v));
}
[Theory]
[MemberData(nameof(MASeriesData))]
public void Period_default(Type classType) {
GBM_Feed data = new(100);
var MA_Series = Activator.CreateInstance(classType, data) as TSeries;
Assert.False(double.IsNaN(MA_Series.Last.v));
}
public static IEnumerable<object[]> MASeriesData()
{
foreach (var type in maSeriesTypes)
{
yield return new object[] { type };
}
}
}
#nullable restore
+4 -4
View File
@@ -33,7 +33,7 @@ public class Skender
[Fact]
public void ADL()
{
ADL_Series QL = new(bars, false);
ADL_Series QL = new(bars);
var SK = quotes.GetAdl().Select(i => i.Adl);
for (int i = QL.Length; i > skip; i--)
{
@@ -228,9 +228,9 @@ public class Skender
}
}
[Fact]
public void LINREG()
public void SLOPE()
{
LINREG_Series QL = new(bars.Close, period, useNaN: false);
SLOPE_Series QL = new(bars.Close, period, useNaN: false);
var SK = quotes.GetSlope(period);
for (int i = QL.Length; i > skip; i--)
{
@@ -447,7 +447,7 @@ public class Skender
[Fact]
public void TR()
{
TR_Series QL = new(bars, useNaN: false);
TR_Series QL = new(bars);
var SK = quotes.GetTr().Select(i => i.Tr.Null2NaN()!);
for (int i = QL.Length; i > skip; i--)
{
+2 -2
View File
@@ -48,7 +48,7 @@ public class Ta_Lib
[Fact]
public void ADL()
{
ADL_Series QL = new(bars, false);
ADL_Series QL = new(bars);
Core.Ad(inhigh, inlow, inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
for (int i = QL.Length - 1; i > 0; i--)
{
@@ -424,7 +424,7 @@ public class Ta_Lib
[Fact]
public void TR()
{
TR_Series QL = new(bars, false);
TR_Series QL = new(bars);
Core.TRange(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
for (int i = QL.Length - 1; i > skip; i--)
{
+3 -3
View File
@@ -36,7 +36,7 @@ public class Tulip_Test
{
double[][] arrin = {inhigh, inlow, inclose, involume };
double[][] arrout = { outdata };
ADL_Series QL = new(bars, false);
ADL_Series QL = new(bars);
Tulip.Indicators.ad.Run(inputs: arrin, options: new double[] { }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--)
{
@@ -274,7 +274,7 @@ public class Tulip_Test
public void LINREG() {
double[][] arrin = { inclose };
double[][] arrout = { outdata };
LINREG_Series QL = new(bars.Close, period);
SLOPE_Series QL = new(bars.Close, period);
Tulip.Indicators.linregslope.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
@@ -438,7 +438,7 @@ public class Tulip_Test
public void TR() {
double[][] arrin = { inhigh,inlow,inclose };
double[][] arrout = { outdata };
TR_Series QL = new(bars, false);
TR_Series QL = new(bars);
Tulip.Indicators.tr.Run(inputs: arrin, options: new double[] {}, outputs: arrout);
for (int i = QL.Length - 1; i > skip; i--) {
double QL_item = QL[i].v;
+2 -1
View File
@@ -33,8 +33,9 @@
|EDECAY - Exponential Decay|`DECAY_Series`|||decay|✔️edecay|
|ENTROPY - Entropy|`ENTROPY_Series`|||entropy||
|KURTOSIS - Kurtosis|`KURT_Series`|||✔️kurtosis|
|LINREG - Linear Regression|`LINREG_Series`||✔️GetSlope||✔️linregslope|
|SLOPE - Slope of Linear Regression|`SLOPE_Series`||✔️GetSlope||✔️linregslope|
|MAD - Mean Absolute Deviation|`MAD_Series`||✔️GetSmaAnalysis|✔️mad|
|MAE - Mean Absolute Error|`MAE_Series`||||
|MAPE - Mean Absolute Percent Error|`MAPE_Series`||✔️GetSmaAnalysis||
|MEDIAN - Median value|`MEDIAN_Series`|||✔️median|
|MSE - Mean Squared Error|`MSE_Series`||✔️GetSmaAnalysis||