mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-28 01:37:43 +00:00
Update main automation workflow to use wildcard for dotcover report path
This commit is contained in:
@@ -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); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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,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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -26,6 +26,8 @@ public class Indicators
|
||||
typeof(T3_Series),
|
||||
typeof(KAMA_Series),
|
||||
typeof(TRIMA_Series),
|
||||
typeof(MAMA_Series),
|
||||
typeof(HWMA_Series),
|
||||
};
|
||||
|
||||
[Theory]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
@@ -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--)
|
||||
{
|
||||
|
||||
@@ -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--)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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||
|
||||
|
||||
Reference in New Issue
Block a user