Merge branch 'dev' into main

This commit is contained in:
Miha Kralj
2022-11-11 21:21:12 -08:00
77 changed files with 556 additions and 628 deletions
+14
View File
@@ -87,6 +87,20 @@ jobs:
title: "Latest Build" title: "Latest Build"
files: /Quantower/Settings/Scripts/Indicators/QuanTAlib/*.dll files: /Quantower/Settings/Scripts/Indicators/QuanTAlib/*.dll
- name: Authenticate to Github packages source
run: dotnet nuget add source
--username mihakralj
--password ${{ secrets.GITHUB_TOKEN }}
--store-password-in-clear-text
--name github "https://nuget.pkg.github.com/mihakralj/index.json"
- name: Push package to github
if: ${{ github.ref == 'refs/heads/dev' }}
run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg'
--source https://nuget.pkg.github.com/mihakralj/index.json
--skip-duplicate
--no-symbols
- name: Push package to nuget.org - name: Push package to nuget.org
if: ${{ github.ref == 'refs/heads/main' }} if: ${{ github.ref == 'refs/heads/main' }}
run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg' run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg'
+2 -2
View File
@@ -30,8 +30,8 @@ public class ATR_chart : Indicator
this.ShortName = "ATR (" + this.Period + ")"; this.ShortName = "ATR (" + this.Period + ")";
this.bars = new(); this.bars = new();
this.indicator = new(source: bars, period: this.Period, useNaN: false); this.indicator = new(source: bars, period: this.Period, useNaN: false);
} }
protected override void OnUpdate(UpdateArgs args) protected override void OnUpdate(UpdateArgs args)
{ {
bool update = !(args.Reason == UpdateReason.NewBar || bool update = !(args.Reason == UpdateReason.NewBar ||
-5
View File
@@ -51,11 +51,6 @@ public class WMAPE_chart : Indicator
this.bars.Add(this.Time(), this.GetPrice(PriceType.Open), this.GetPrice(PriceType.High), this.GetPrice(PriceType.Low), this.GetPrice(PriceType.Close), this.GetPrice(PriceType.Volume), update); this.bars.Add(this.Time(), this.GetPrice(PriceType.Open), this.GetPrice(PriceType.High), this.GetPrice(PriceType.Low), this.GetPrice(PriceType.Close), this.GetPrice(PriceType.Volume), update);
double result = this.indicator[this.indicator.Count - 1].v; double result = this.indicator[this.indicator.Count - 1].v;
this.SetValue(result, 0); this.SetValue(result, 0);
} }
} }
-93
View File
@@ -1,93 +0,0 @@
using System.Collections;
using System.Drawing;
using System.Drawing.Text;
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class ZLMA_chart : Indicator
{
#region Parameters
[InputParameter("Smoothing period", 0, 1, 999, 1, 1)]
private readonly int Period = 10;
[InputParameter("Data source", 1, variants: new object[]
{ "Open", 0, "High", 1, "Low", 2, "Close", 3, "HL2", 4, "OC2", 5,
"OHL3", 6, "HLC3", 7, "OHLC4", 8, "Weighted (HLCC4)", 9 })]
private readonly int DataSource = 3;
[InputParameter("MA algorithm", 2, variants: new object[]
{ "SMA", 0,
"WMA", 1,
"EMA", 2,
"DEMA", 3,
"TEMA", 4,
"HMA", 5,
"KAMA", 6,
"JMA", 7,
"SMMA", 8
})]
private readonly int matype = 2;
#endregion Parameters
private TBars bars;
///////
private TSeries indicator;
///////
public ZLMA_chart()
{
this.SeparateWindow = false;
this.Name = "ZLMA - Zero-lag Moving Average";
this.Description = "Zero-Lag Moving Average description";
this.AddLineSeries("ZLMA", Color.RoyalBlue, 3, LineStyle.Solid);
}
protected override void OnInit()
{
this.bars = new();
string maname = matype switch
{
0 => "SMA",
1 => "WMA",
2 => "EMA",
3 => "DEMA",
4 => "TEMA",
5 => "HMA",
6 => "KAMA",
7 => "JMA",
8 => "SMMA",
_ => "???"
};
this.ShortName = "ZLMA (" + maname + ", " + TBars.SelectStr(this.DataSource) + ", " + this.Period + ")";
ZL_Series zerolag = new(source: bars.Select(this.DataSource), period: this.Period, useNaN: false);
this.indicator = matype switch
{
0 => new SMA_Series(source: zerolag, period: this.Period, useNaN: false),
1 => new WMA_Series(source: zerolag, period: this.Period, useNaN: false),
2 => new EMA_Series(source: zerolag, period: this.Period, useNaN: false),
3 => new DEMA_Series(source: zerolag, period: this.Period, useNaN: false),
4 => new TEMA_Series(source: zerolag, period: this.Period, useNaN: false),
5 => new HMA_Series(source: zerolag, period: this.Period, useNaN: false),
6 => new KAMA_Series(source: zerolag, period: this.Period, useNaN: false),
7 => new JMA_Series(source: zerolag, period: this.Period, useNaN: false),
8 => new SMMA_Series(source: zerolag, period: this.Period, useNaN: false),
_ => new EMA_Series(source: zerolag, period: this.Period, useNaN: false)
};
}
protected override void OnUpdate(UpdateArgs args)
{
bool update = !(args.Reason == UpdateReason.NewBar ||
args.Reason == UpdateReason.HistoricalBar);
this.bars.Add(this.Time(), this.GetPrice(PriceType.Open),
this.GetPrice(PriceType.High), this.GetPrice(PriceType.Low),
this.GetPrice(PriceType.Close),
this.GetPrice(PriceType.Volume), update);
double result = this.indicator[this.indicator.Count-1].v;
this.SetValue(result);
}
}
+17 -51
View File
@@ -32,23 +32,14 @@ public abstract class Single_TSeries_Indicator : TSeries
public new virtual void Add((System.DateTime t, double v) TValue, bool update) => base.Add(TValue, update); public new virtual void Add((System.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) // potentially overridable Add() method for the whole series (could be replaced with faster bulk algo)
public virtual void Add(TSeries data) public virtual void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { this.Add(TValue: data[i], update: false); }}
{
for (int i = 0; i < data.Count; i++) { this.Add(TValue: data[i], update: false); }
}
public new void Add((System.DateTime t, double v) TValue) public new void Add((System.DateTime t, double v) TValue) => this.Add(TValue: TValue, update: false);
=> 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(bool update) public void Add() => this.Add(TValue: this._data[this._data.Count - 1], update: false);
=> this.Add(TValue: this._data[this._data.Count - 1], update: update); public new void Sub(object source, TSeriesEventArgs e) => this.Add(TValue: this._data[this._data.Count - 1], update: e.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);
} }
public abstract class Pair_TSeries_Indicator : TSeries public abstract class Pair_TSeries_Indicator : TSeries
{ {
protected readonly TSeries _d1; protected readonly TSeries _d1;
@@ -83,24 +74,14 @@ public abstract class Pair_TSeries_Indicator : TSeries
} }
// overridable Add(Tvalue, Tvalue) method to add/update a single value at the end of the list // 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) 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
=> base.Add(TValue: (TValue1.t, 0), update: update); // default inserts zeros
// potentially overridable Add() bulk variations (could be replaced with faster bulk algos) // potentially overridable Add() bulk variations (could be replaced with faster bulk algos)
public virtual void Add(TSeries d1, TSeries d2) { public virtual void Add(TSeries d1, TSeries d2) { for (int i = 0; i < d1.Count; i++) { this.Add(d1[i], d2[i], update: false); }}
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); }}
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); }
}
public void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2) => this.Add(TValue1, TValue2, update: false);
public void Add((System.DateTime t, double v)TValue1, (System.DateTime t, double v)TValue2)
=> this.Add(TValue1, TValue2, update: false);
public void Add(bool update) public void Add(bool update)
{ {
@@ -123,12 +104,9 @@ public abstract class Pair_TSeries_Indicator : TSeries
} }
public void Add() => this.Add(update: false); public void Add() => this.Add(update: false);
public new void Sub(object source, TSeriesEventArgs e) => this.Add(e.update);
public new void Sub(object source, TSeriesEventArgs e)
=> this.Add(e.update);
} }
public abstract class Single_TBars_Indicator : TSeries public abstract class Single_TBars_Indicator : TSeries
{ {
protected readonly int _p; protected readonly int _p;
@@ -148,22 +126,10 @@ public abstract class Single_TBars_Indicator : TSeries
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 o, double h, double l, double c, double v) TBar, bool update) => base.Add((TBar.t, 0.0), update);
// potentially overridable Add() method for the whole bars or series (could be replaced with faster bulk algo) // potentially overridable Add() method for the whole bars or series (could be replaced with faster bulk algo)
public virtual void Add(TBars bars) public virtual void Add(TBars bars) { for (int i = 0; i < bars.Count; i++) { this.Add(TBar: bars[i], update: false); }}
{ public virtual void Add(TSeries data) { for (int i = 0; i < data.Count; i++) { base.Add(TValue: data[i], update: false); }}
for (int i = 0; i < bars.Count; i++) { this.Add(TBar: bars[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 virtual void Add(TSeries data) public new void Sub(object source, TSeriesEventArgs e) => this.Add(TBar: this._bars[this._bars.Count - 1], update: e.update);
{
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);
} }
+4 -1
View File
@@ -22,7 +22,10 @@ public class MAX_Series : Single_TSeries_Indicator
double _max = TValue.v; double _max = TValue.v;
for (int i = 0; i < this._buffer.Count; i++) for (int i = 0; i < this._buffer.Count; i++)
{ _max = (this._buffer[i] > _max) ? this._buffer[i] : _max; } {
//_max = (this._buffer[i] > _max) ? this._buffer[i] : _max;
_max = Math.Max(this._buffer[i], _max);
}
var result = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _max); var result = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _max);
+4 -1
View File
@@ -22,7 +22,10 @@ public class MIN_Series : Single_TSeries_Indicator
double _min = TValue.v; double _min = TValue.v;
for (int i = 0; i < this._buffer.Count; i++) for (int i = 0; i < this._buffer.Count; i++)
{ _min = (this._buffer[i] < _min) ? this._buffer[i] : _min; } {
//_min = (this._buffer[i] < _min) ? this._buffer[i] : _min;
_min = Math.Min(this._buffer[i], _min);
}
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _min); var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _min);
-3
View File
@@ -75,7 +75,6 @@ public class TBars : System.Collections.Generic.List<(DateTime t, double o, doub
}; };
} }
public void Add((DateTime t, double o, double h, double l, double c, double v) i, bool update = false) public void Add((DateTime t, double o, double h, double l, double c, double v) i, bool update = false)
=> Add(i.t, i.o, i.h, i.l, i.c, i.v, update); => Add(i.t, i.o, i.h, i.l, i.c, i.v, update);
@@ -130,6 +129,4 @@ public class TBars : System.Collections.Generic.List<(DateTime t, double o, doub
Pub(this, new TSeriesEventArgs { update = update }); Pub(this, new TSeriesEventArgs { update = update });
} }
} }
} }
-1
View File
@@ -30,6 +30,5 @@ public class ZL_Series : Single_TSeries_Indicator
var ret = (TValue.t, (base.Count==0 && base._NaN) ? double.NaN : _zl ); var ret = (TValue.t, (base.Count==0 && base._NaN) ? double.NaN : _zl );
base.Add(ret, update); base.Add(ret, update);
} }
} }
-1
View File
@@ -55,4 +55,3 @@ public class Alphavantage_Feed : TBars
return (date, o, h, l, c, v); return (date, o, h, l, c, v);
} }
} }
+3 -3
View File
@@ -38,11 +38,11 @@ public class GBM_Feed : TBars
double OCMax = Math.Max(Open,Close); double OCMax = Math.Max(Open,Close);
double High = (GBM_value(seed, volatility*0.5, 0)); double High = (GBM_value(seed, volatility*0.5, 0));
High = (High<OCMax)? 2*OCMax-High : High; High = (High<OCMax)? (2 * OCMax) - High : High;
double OCMin = Math.Min(Open,Close); double OCMin = Math.Min(Open,Close);
double Low = (GBM_value(seed, volatility*0.5, 0)); double Low = (GBM_value(seed, volatility*0.5, 0));
Low = (Low>OCMin)? 2*OCMin-Low : Low; Low = (Low>OCMin)? (2 * OCMin) - Low : Low;
double Volume = GBM_value(seed*10, volatility*2, Drift:0); double Volume = GBM_value(seed*10, volatility*2, Drift:0);
@@ -55,6 +55,6 @@ public class GBM_Feed : TBars
double U1 = 1.0-rnd.NextDouble(); double U1 = 1.0-rnd.NextDouble();
double U2 = 1.0-rnd.NextDouble(); double U2 = 1.0-rnd.NextDouble();
double Z = Math.Sqrt(-2.0 * Math.Log(U1)) * Math.Sin(2.0 * Math.PI * U2); double Z = Math.Sqrt(-2.0 * Math.Log(U1)) * Math.Sin(2.0 * Math.PI * U2);
return Seed * Math.Exp( Drift - (Volatility*Volatility*0.5) + Volatility * Z); return Seed * Math.Exp( Drift - (Volatility*Volatility*0.5) + (Volatility * Z));
} }
} }
+4 -4
View File
@@ -17,10 +17,10 @@ public class RND_Feed : TBars
double c = startvalue; double c = startvalue;
for (int i = 0; i < bars; i++) for (int i = 0; i < bars; i++)
{ {
double o = Math.Round(c + c * (volatility * 0.1 * rnd.NextDouble() - 0.005), 2); double o = Math.Round(c + (c * (((volatility * 0.1) * rnd.NextDouble()) - 0.005)), 2);
double h = Math.Round(o + c * volatility * rnd.NextDouble(), 2); double h = Math.Round(o + (c * volatility * rnd.NextDouble()), 2);
double l = Math.Round(o - c * volatility * rnd.NextDouble(), 2); double l = Math.Round(o - (c * volatility * rnd.NextDouble()), 2);
c = Math.Round(l + (h - l) * rnd.NextDouble(), 2); c = Math.Round(l + ((h - l) * rnd.NextDouble()), 2);
double v = Math.Round(1000 * rnd.NextDouble(), 2); double v = Math.Round(1000 * rnd.NextDouble(), 2);
this.Add(DateTime.Today.AddDays(i - bars), o, h, l, c, v); this.Add(DateTime.Today.AddDays(i - bars), o, h, l, c, v);
} }
@@ -20,14 +20,13 @@ public class CCI_Series : Single_TBars_Indicator
{ {
private readonly System.Collections.Generic.List<double> _tp = new(); private readonly System.Collections.Generic.List<double> _tp = new();
public CCI_Series(TBars source, int period = 10, bool useNaN = false) public CCI_Series(TBars source, int period = 10, bool useNaN = false) : base(source, period: period, useNaN: useNaN)
: base(source, period: period, useNaN: useNaN) { {
if (_bars.Count > 0) { base.Add(_bars); } 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) { 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; 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 (update) { this._tp[this._tp.Count - 1] = _tpItem; } else { this._tp.Add(_tpItem); }
if (this._tp.Count > this._p) { this._tp.RemoveAt(0); } if (this._tp.Count > this._p) { this._tp.RemoveAt(0); }
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<Version>0.1.17</Version> <Version>0.1.18</Version>
<releaseNotes> <releaseNotes>
</releaseNotes> </releaseNotes>
<Title>QuanTAlib</Title> <Title>QuanTAlib</Title>
+1 -1
View File
@@ -54,7 +54,7 @@ public class KURT_Series : Single_TSeries_Indicator
} }
double _Vx = _s2 / (_n - 1); double _Vx = _s2 / (_n - 1);
double _kurt = (_n > 3) ? (((_n * (_n + 1)) / ((_n - 1) * (_n - 2) * (_n - 3))) * (_s4 / (_Vx * _Vx)) - (3 * ((_n - 1) * (_n - 1) / ((_n - 2) * (_n - 3))))) : Double.NaN; double _kurt = (_n > 3) ? ((((_n * (_n + 1)) / (((_n - 1) * (_n - 2)) * (_n - 3))) * (_s4 / (_Vx * _Vx))) - (3 * (((_n - 1) * (_n - 1)) / ((_n - 2) * (_n - 3))))) : Double.NaN;
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? Double.NaN : _kurt); var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? Double.NaN : _kurt);
base.Add(result, update); base.Add(result, update);
+1 -1
View File
@@ -37,7 +37,7 @@ public class MED_Series : Single_TSeries_Indicator
System.Collections.Generic.List<double> _s = new(this._buffer); System.Collections.Generic.List<double> _s = new(this._buffer);
_s.Sort(); _s.Sort();
int _p1 = _s.Count / 2; int _p1 = _s.Count / 2;
int _p2 = Math.Max(0, _s.Count / 2 - 1); int _p2 = Math.Max(0, (_s.Count / 2) - 1);
double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2; double _med = (_s.Count % 2 != 0) ? _s[_p1] : (_s[_p1] + _s[_p2]) / 2;
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _med); var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _med);
@@ -1,68 +1,65 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
ALMA: Arnaud Legoux Moving Average ALMA: Arnaud Legoux Moving Average
The ALMA moving average uses the curve of the Normal (Gauss) distribution, which The ALMA moving average uses the curve of the Normal (Gauss) distribution, which
can be shifted from 0 to 1. This allows regulating the smoothness and high can be shifted from 0 to 1. This allows regulating the smoothness and high
sensitivity of the indicator. Sigma is another parameter that is responsible for sensitivity of the indicator. Sigma is another parameter that is responsible for
the shape of the curve coefficients. This moving average reduces lag of the data the shape of the curve coefficients. This moving average reduces lag of the data
in conjunction with smoothing to reduce noise. in conjunction with smoothing to reduce noise.
Sources: Sources:
https://phemex.com/academy/what-is-arnaud-legoux-moving-averages https://phemex.com/academy/what-is-arnaud-legoux-moving-averages
https://www.prorealcode.com/prorealtime-indicators/alma-arnaud-legoux-moving-average/ https://www.prorealcode.com/prorealtime-indicators/alma-arnaud-legoux-moving-average/
</summary> */ </summary> */
public class ALMA_Series : Single_TSeries_Indicator public class ALMA_Series : Single_TSeries_Indicator
{ {
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly double[] _weight; private readonly double[] _weight;
private double _norm; private double _norm;
private readonly double _offset, _sigma; private readonly double _offset, _sigma;
public ALMA_Series(TSeries source, int period, double offset = 0.85, double sigma = 6.0, bool useNaN = false) public ALMA_Series(TSeries source, int period, double offset = 0.85, double sigma = 6.0, bool useNaN = false)
: base(source, period, useNaN) : base(source, period, useNaN)
{ {
_offset = offset; _offset = offset;
_sigma = sigma; _sigma = sigma;
_weight = new double[period]; _weight = new double[period];
if (this._data.Count > 0) { base.Add(this._data); } if (this._data.Count > 0) { base.Add(this._data); }
} }
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; } if (update) { this._buffer[this._buffer.Count - 1] = TValue.v; }
else { this._buffer.Add(TValue.v); } else { this._buffer.Add(TValue.v); }
if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); } if (this._buffer.Count > this._p) { this._buffer.RemoveAt(0); }
if (this._buffer.Count <= _p) { calc_weights(); } if (this._buffer.Count <= _p) { calc_weights(); }
double _weightedSum = 0; double _weightedSum = 0;
for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; } for (int i = 0; i < this._buffer.Count; i++) { _weightedSum += _weight[i] * _buffer[i]; }
double _alma = _weightedSum / _norm; double _alma = _weightedSum / _norm;
var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _alma); var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _alma);
base.Add(ret, update); base.Add(ret, update);
} }
private void calc_weights() private void calc_weights()
{ {
int _len = this._buffer.Count; int _len = this._buffer.Count;
_norm = 0; _norm = 0;
double _m = _offset * (_len - 1); double _m = _offset * (_len - 1);
double _s = _len / _sigma; double _s = _len / _sigma;
for (int i = 0; i < _len; i++) for (int i = 0; i < _len; i++)
{ {
double _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s)); double _wt = Math.Exp(-((i - _m) * (i - _m)) / (2 * _s * _s));
_weight[i] = _wt; _weight[i] = _wt;
_norm += _wt; _norm += _wt;
} }
} }
}
}
@@ -31,7 +31,6 @@ public class DEMA_Series : Single_TSeries_Indicator
public override void Add((DateTime t, double v) TValue, bool update) public override void Add((DateTime t, double v) TValue, bool update)
{ {
if (update) if (update)
{ {
this._lastema1 = this._lastlastema1; this._lastema1 = this._lastlastema1;
@@ -53,15 +52,14 @@ public class DEMA_Series : Single_TSeries_Indicator
for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; }
_sma /= this._buffer.Count; _sma /= this._buffer.Count;
_ema1 = _ema2 = _sma; _ema1 = _ema2 = _sma;
} }
else else
{ {
_ema1 = TValue.v * this._k + this._lastema1 * this._k1m; _ema1 = (TValue.v * this._k) + (this._lastema1 * this._k1m);
_ema2 = _ema1 * this._k + this._lastema2 * this._k1m; _ema2 = (_ema1 * this._k) + (this._lastema2 * this._k1m);
} }
double _dema = 2 * _ema1 - _ema2; double _dema = (2 * _ema1) - _ema2;
this._lastlastema1 = this._lastema1; this._lastlastema1 = this._lastema1;
this._lastlastema2 = this._lastema2; this._lastlastema2 = this._lastema2;
this._lastema1 = _ema1; this._lastema1 = _ema1;
@@ -52,7 +52,7 @@ public class EMA_Series : Single_TSeries_Indicator
} }
else else
{ {
_ema = TValue.v * this._k + this._lastema * this._k1m; _ema = (TValue.v * this._k) + (this._lastema * this._k1m);
} }
this._lastlastema = this._lastema; this._lastlastema = this._lastema;
@@ -1,65 +1,65 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
KAMA: Kaufman's Adaptive Moving Average KAMA: Kaufman's Adaptive Moving Average
Created in 1988 by American quantitative finance theorist Perry J. Kaufman and is known as Created in 1988 by American quantitative finance theorist Perry J. Kaufman and is known as
Kaufman's Adaptive Moving Average (KAMA). Even though the method was developed as early as 1972, Kaufman's Adaptive Moving Average (KAMA). Even though the method was developed as early as 1972,
it was not until the popular book titled "Trading Systems and Methods" that it was made widely it was not until the popular book titled "Trading Systems and Methods" that it was made widely
available to the public. Unlike other conventional moving averages systems, the Kaufman's Adaptive available to the public. Unlike other conventional moving averages systems, the Kaufman's Adaptive
Moving Average, considers market volatility apart from price fluctuations. Moving Average, considers market volatility apart from price fluctuations.
KAMAi = KAMAi - 1 + SC * ( price - KAMAi-1 ) KAMAi = KAMAi - 1 + SC * ( price - KAMAi-1 )
Sources: Sources:
https://www.tutorialspoint.com/kaufman-s-adaptive-moving-average-kama-formula-and-how-does-it-work https://www.tutorialspoint.com/kaufman-s-adaptive-moving-average-kama-formula-and-how-does-it-work
https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/kaufmans-adaptive-moving-average-kama/ https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/kaufmans-adaptive-moving-average-kama/
https://www.technicalindicators.net/indicators-technical-analysis/152-kama-kaufman-adaptive-moving-average https://www.technicalindicators.net/indicators-technical-analysis/152-kama-kaufman-adaptive-moving-average
Remark: Remark:
If useNaN:true argument is provided, KAMA starts calculating values from [period] bar onwards. If useNaN:true argument is provided, KAMA starts calculating values from [period] bar onwards.
Without useNaN argument (default setting), KAMA starts calculating values from bar 1 - and yields Without useNaN argument (default setting), KAMA starts calculating values from bar 1 - and yields
slightly different results for the first 50 bars - and then converges with the other one. slightly different results for the first 50 bars - and then converges with the other one.
</summary> */ </summary> */
public class KAMA_Series : Single_TSeries_Indicator public class KAMA_Series : Single_TSeries_Indicator
{ {
private readonly double _scFast, _scSlow; private readonly double _scFast, _scSlow;
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
private double _lastkama = double.NaN; private double _lastkama = double.NaN;
private double _lastlastkama; private double _lastlastkama;
public KAMA_Series(TSeries source, int period, int fast = 2, int slow= 30, bool useNaN = false) : base(source, period, useNaN) { public KAMA_Series(TSeries source, int period, int fast = 2, int slow= 30, bool useNaN = false) : base(source, period, useNaN) {
_scFast = 2.0 / (fast+1); _scFast = 2.0 / (fast+1);
_scSlow = 2.0 / (slow+1); _scSlow = 2.0 / (slow+1);
if (base._data.Count > 0) { base.Add(base._data); } if (base._data.Count > 0) { base.Add(base._data); }
} }
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
if (update){ if (update){
_buffer[_buffer.Count - 1] = TValue.v; _buffer[_buffer.Count - 1] = TValue.v;
this._lastkama = this._lastlastkama; this._lastkama = this._lastlastkama;
} else { } else {
_buffer.Add(TValue.v); _buffer.Add(TValue.v);
} }
if (_buffer.Count > _p + 1) { _buffer.RemoveAt(0); } if (_buffer.Count > _p + 1) { _buffer.RemoveAt(0); }
double _kama = 0; double _kama = 0;
if (this.Count < this._p) { if (this.Count < this._p) {
for (int i = 0; i < this._buffer.Count; i++) { _kama += this._buffer[i]; } for (int i = 0; i < this._buffer.Count; i++) { _kama += this._buffer[i]; }
_kama /= this._buffer.Count; _kama /= this._buffer.Count;
} else { } else {
double _change = Math.Abs(_buffer[_buffer.Count - 1] - _buffer[(_buffer.Count > _p + 1) ? 1 : 0]); double _change = Math.Abs(_buffer[_buffer.Count - 1] - _buffer[(_buffer.Count > _p + 1) ? 1 : 0]);
double _sumpv = 0; double _sumpv = 0;
for (int i = 1; i < _buffer.Count; i++) for (int i = 1; i < _buffer.Count; i++)
{ _sumpv += Math.Abs(_buffer[(_buffer.Count > 0) ? i : 0] - _buffer[i - 1]); } { _sumpv += Math.Abs(_buffer[(_buffer.Count > 0) ? i : 0] - _buffer[i - 1]); }
double _er = (_sumpv == 0) ? 0 : _change / _sumpv; double _er = (_sumpv == 0) ? 0 : _change / _sumpv;
double _sc = (_er * (_scFast - _scSlow)) + _scSlow; double _sc = (_er * (_scFast - _scSlow)) + _scSlow;
_kama = (_lastkama + (_sc * _sc * (TValue.v - _lastkama))); _kama = (_lastkama + (_sc * _sc * (TValue.v - _lastkama)));
} }
_lastlastkama = _lastkama; _lastlastkama = _lastkama;
_lastkama = _kama; _lastkama = _kama;
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _kama); var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _kama);
base.Add(result, update); base.Add(result, update);
} }
} }
@@ -51,7 +51,7 @@ public class RMA_Series : Single_TSeries_Indicator
} }
else else
{ {
_ema = TValue.v * _k + _lastema * _k1m; _ema = (TValue.v * _k) + (_lastema * _k1m);
} }
this._lastlastema = this._lastema; this._lastlastema = this._lastema;
@@ -33,7 +33,6 @@ public class TEMA_Series : Single_TSeries_Indicator
public override void Add((DateTime t, double v) TValue, bool update) public override void Add((DateTime t, double v) TValue, bool update)
{ {
if (update) if (update)
{ {
this._lastema1 = this._lastlastema1; this._lastema1 = this._lastlastema1;
@@ -59,12 +58,12 @@ public class TEMA_Series : Single_TSeries_Indicator
} }
else else
{ {
_ema1 = TValue.v * this._k + this._lastema1 * this._k1m; _ema1 = (TValue.v * this._k) + (this._lastema1 * this._k1m);
_ema2 = _ema1 * this._k + this._lastema2 * this._k1m; _ema2 = (_ema1 * this._k) + (this._lastema2 * this._k1m);
_ema3 = _ema2 * this._k + this._lastema3 * this._k1m; _ema3 = (_ema2 * this._k) + (this._lastema3 * this._k1m);
} }
double _tema = 3 * (_ema1 - _ema2) + _ema3; double _tema = (3 * (_ema1 - _ema2)) + _ema3;
this._lastlastema1 = this._lastema1; this._lastlastema1 = this._lastema1;
this._lastlastema2 = this._lastema2; this._lastlastema2 = this._lastema2;
+49
View File
@@ -0,0 +1,49 @@
namespace QuanTAlib;
using System;
/* <summary>
TRIMA: Triangular Moving Average
A weighted moving average where the shape of the weights are triangular and the greatest
weight is in the middle of the period,
Sources:
https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/triangular-moving-average-trima/
Remark:
trima = sma(sma(signal, n/2), n/2)
</summary> */
public class TRIMA_Series : Single_TSeries_Indicator
{
private readonly System.Collections.Generic.List<double> _buffer1 = new();
private readonly System.Collections.Generic.List<double> _buffer2 = new();
private readonly int _p1a, _p1b;
public TRIMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{
_p1a = (int) Math.Floor((period * 0.5) + 1);
_p1b = (int) Math.Ceiling(0.5 * period);
if (base._data.Count > 0) { base.Add(base._data); }
}
public override void Add((System.DateTime t, double v) TValue, bool update)
{
if (update) { _buffer1[_buffer1.Count - 1] = TValue.v; } else { _buffer1.Add(TValue.v); }
if (_buffer1.Count > this._p1b && this._p1b != 0) { _buffer1.RemoveAt(0); }
double _sma1 = 0;
for (int i = 0; i < _buffer1.Count; i++) { _sma1 += _buffer1[i]; }
_sma1 /= this._buffer1.Count;
if (update) { _buffer2[_buffer2.Count - 1] = _sma1; } else { _buffer2.Add(_sma1); }
if (_buffer2.Count > this._p1a && this._p1a != 0) { _buffer2.RemoveAt(0); }
double _trima = 0;
for (int i = 0; i < _buffer2.Count; i++) { _trima += _buffer2[i]; }
_trima /= this._buffer2.Count;
var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _trima);
base.Add(result, update);
}
}
@@ -1,72 +1,72 @@
namespace QuanTAlib; namespace QuanTAlib;
using System; using System;
/* <summary> /* <summary>
ZLEMA: Zero Lag Exponential Moving Average ZLEMA: Zero Lag Exponential Moving Average
The Zero lag exponential moving average (ZLEMA) indicator was created by John The Zero lag exponential moving average (ZLEMA) indicator was created by John
Ehlers and Ric Way. Ehlers and Ric Way.
The formula for a given N-Day period and for a given Data series is: The formula for a given N-Day period and for a given Data series is:
Lag = (Period-1)/2 Lag = (Period-1)/2
Ema Data = {Data+(Data-Data(Lag days ago)) Ema Data = {Data+(Data-Data(Lag days ago))
ZLEMA = EMA (EmaData,Period) ZLEMA = EMA (EmaData,Period)
Remark: Remark:
The idea is do a regular exponential moving average (EMA) calculation but on a The idea is do a regular exponential moving average (EMA) calculation but on a
de-lagged data instead of doing it on the regular data. Data is de-lagged by de-lagged data instead of doing it on the regular data. Data is de-lagged by
removing the data from "lag" days ago thus removing (or attempting to remove) removing the data from "lag" days ago thus removing (or attempting to remove)
the cumulative lag effect of the moving average. the cumulative lag effect of the moving average.
</summary> */ </summary> */
public class ZLEMA_Series : Single_TSeries_Indicator public class ZLEMA_Series : Single_TSeries_Indicator
{ {
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly double _k, _k1m; private readonly double _k, _k1m;
private double _lastema, _lastlastema; private double _lastema, _lastlastema;
public ZLEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) public ZLEMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
{ {
this._k = 2.0 / (this._p + 1); this._k = 2.0 / (this._p + 1);
this._k1m = 1.0 - this._k; this._k1m = 1.0 - this._k;
this._lastema = this._lastlastema = double.NaN; this._lastema = this._lastlastema = double.NaN;
if (base._data.Count > 0) if (base._data.Count > 0)
{ base.Add(base._data); } { base.Add(base._data); }
} }
public override void Add((System.DateTime t, double v) TValue, bool update) public override void Add((System.DateTime t, double v) TValue, bool update)
{ {
int _lag = (int)((_p-1) * 0.5); int _lag = (int)((_p-1) * 0.5);
_lag = (this.Count-_lag < 0) ? 0 : this.Count-_lag; _lag = (this.Count-_lag < 0) ? 0 : this.Count-_lag;
double _zl = TValue.v + (TValue.v - _data[_lag].v); double _zl = TValue.v + (TValue.v - _data[_lag].v);
double _ema = 0; double _ema = 0;
if (update) if (update)
{ this._lastema = this._lastlastema; } { this._lastema = this._lastlastema; }
if (this.Count < this._p) if (this.Count < this._p)
{ {
if (update) if (update)
{ this._buffer[this._buffer.Count - 1] = _zl; } { this._buffer[this._buffer.Count - 1] = _zl; }
else else
{ {
this._buffer.Add(_zl); this._buffer.Add(_zl);
} }
if (this._buffer.Count > this._p) if (this._buffer.Count > this._p)
{ this._buffer.RemoveAt(0); } { this._buffer.RemoveAt(0); }
for (int i = 0; i < this._buffer.Count; i++) for (int i = 0; i < this._buffer.Count; i++)
{ _ema += this._buffer[i]; } { _ema += this._buffer[i]; }
_ema /= this._buffer.Count; _ema /= this._buffer.Count;
} }
else else
{ {
_ema = _zl * this._k + this._lastema * this._k1m; _ema = (_zl * this._k) + (this._lastema * this._k1m);
} }
this._lastlastema = this._lastema; this._lastlastema = this._lastema;
this._lastema = _ema; this._lastema = _ema;
var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema); var ret = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema);
base.Add(ret, update); base.Add(ret, update);
} }
} }
@@ -50,7 +50,7 @@ public class ATRP_Series : Single_TBars_Indicator
for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; }
_ema /= this._buffer.Count; _ema /= this._buffer.Count;
} }
else { _ema = d.v * _k + _lastema * _k1m; } else { _ema = (d.v * _k) + (_lastema * _k1m); }
this._lastlastema = this._lastema; this._lastlastema = this._lastema;
this._lastema = _ema; this._lastema = _ema;
@@ -13,7 +13,6 @@ Sources:
</summary> */ </summary> */
public class ATR_Series : Single_TBars_Indicator public class ATR_Series : Single_TBars_Indicator
{ {
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
@@ -53,7 +52,7 @@ public class ATR_Series : Single_TBars_Indicator
for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; } for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; }
_ema /= this._buffer.Count; _ema /= this._buffer.Count;
} }
else { _ema = d.v * _k + _lastema * _k1m; } else { _ema = (d.v * _k) + (_lastema * _k1m); }
this._lastlastema = this._lastema; this._lastlastema = this._lastema;
this._lastema = _ema; this._lastema = _ema;
+62
View File
@@ -0,0 +1,62 @@
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; }
// Unclear what the first value in OBV series is - currently set to volume[0]
// if (this.Count == 0) { _obv = 0; }
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);
}
}
-1
View File
@@ -108,6 +108,5 @@ public class TBars_Test
s.Add(DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false); s.Add(DateTime.Today, 0.1, 1.1, 2.1, 3.1, 4.1, false);
Assert.Equal(s.Close.v, t.v); Assert.Equal(s.Close.v, t.v);
Assert.Equal(s.Close.Count, t.Count); Assert.Equal(s.Close.Count, t.Count);
} }
} }
-2
View File
@@ -48,7 +48,6 @@ public class TSeries_Test
TSeries t = s; TSeries t = s;
Assert.Equal(5, (double)t); Assert.Equal(5, (double)t);
Assert.Equal(5, t.Count); Assert.Equal(5, t.Count);
} }
[Fact] [Fact]
public void BroadcastingEvents() public void BroadcastingEvents()
@@ -58,6 +57,5 @@ public class TSeries_Test
s.Pub += t.Sub; s.Pub += t.Sub;
s.Add(0.0, update: true); s.Add(0.0, update: true);
Assert.Equal(0.0, (double)t); Assert.Equal(0.0, (double)t);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class ALMA_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -52,7 +52,5 @@ public class BBANDS_Test
Assert.Equal(a.Count, c.PercentB.Count); Assert.Equal(a.Count, c.PercentB.Count);
Assert.Equal(a.Count, c.Zscore.Count); Assert.Equal(a.Count, c.Zscore.Count);
Assert.Equal(a.Count, c.Bandwidth.Count); Assert.Equal(a.Count, c.Bandwidth.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class DEMA_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class EMA_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class HEMA_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class HMA_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class JMA_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class KAMA_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class MACD_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class RMA_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class RSI_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class SMA_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class SMMA_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class TEMA_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class WMA_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class ZLEMA_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class BIAS_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class KURT_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class ENTP_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class LINREG_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class MAD_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class MAPE_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class MAX_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class MED_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class MIN_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class MSE_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class PSDEV_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class PVAR_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class SDEV_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class SMAPE_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class VAR_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-2
View File
@@ -27,7 +27,5 @@ public class WMAPE_Test
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
a.Add(double.PositiveInfinity); a.Add(double.PositiveInfinity);
Assert.Equal(a.Count, c.Count); Assert.Equal(a.Count, c.Count);
} }
} }
-3
View File
@@ -1,5 +1,3 @@
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
@@ -120,5 +118,4 @@ public class PandasTA
Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); Assert.Equal(System.Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7));
} }
*/ */
} }
+47 -38
View File
@@ -3,7 +3,6 @@ using QuanTAlib;
using Skender.Stock.Indicators; using Skender.Stock.Indicators;
using Xunit; using Xunit;
namespace Validation; namespace Validation;
public class Skender_Stock public class Skender_Stock
{ {
@@ -14,7 +13,7 @@ public class Skender_Stock
public Skender_Stock() public Skender_Stock()
{ {
this.bars = new(1000); this.bars = new(Bars: 1, Volatility:0.7, Drift:0.0);
this.period = this.rnd.Next(28) + 3; this.period = this.rnd.Next(28) + 3;
this.quotes = this.bars.Select( this.quotes = this.bars.Select(
q => new Quote q => new Quote
@@ -34,7 +33,7 @@ public class Skender_Stock
SMA_Series QL = new(this.bars.Close, this.period, false); SMA_Series QL = new(this.bars.Close, this.period, false);
var SK = this.quotes.GetSma(this.period); var SK = this.quotes.GetSma(this.period);
Assert.Equal(Math.Round((double)SK.Last().Sma!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -43,7 +42,7 @@ public class Skender_Stock
EMA_Series QL = new(this.bars.Close, this.period, false); EMA_Series QL = new(this.bars.Close, this.period, false);
var SK = this.quotes.GetEma(this.period); var SK = this.quotes.GetEma(this.period);
Assert.Equal(Math.Round((double)SK.Last().Ema!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Ema!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
public void WMA() public void WMA()
@@ -51,7 +50,7 @@ public class Skender_Stock
WMA_Series QL = new(this.bars.Close, this.period, false); WMA_Series QL = new(this.bars.Close, this.period, false);
var SK = this.quotes.GetWma(this.period); var SK = this.quotes.GetWma(this.period);
Assert.Equal(Math.Round((double)SK.Last().Wma!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Wma!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -60,7 +59,7 @@ public class Skender_Stock
DEMA_Series QL = new(this.bars.Close, this.period, false); DEMA_Series QL = new(this.bars.Close, this.period, false);
var SK = this.quotes.GetDema(this.period); var SK = this.quotes.GetDema(this.period);
Assert.Equal(Math.Round((double)SK.Last().Dema!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Dema!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -69,7 +68,7 @@ public class Skender_Stock
TEMA_Series QL = new(this.bars.Close, this.period, false); TEMA_Series QL = new(this.bars.Close, this.period, false);
var SK = this.quotes.GetTema(this.period); var SK = this.quotes.GetTema(this.period);
Assert.Equal(Math.Round((double)SK.Last().Tema!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Tema!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -78,7 +77,7 @@ public class Skender_Stock
MAD_Series QL = new(this.bars.Close, this.period, false); MAD_Series QL = new(this.bars.Close, this.period, false);
var SK = this.quotes.GetSmaAnalysis(this.period); var SK = this.quotes.GetSmaAnalysis(this.period);
Assert.Equal(Math.Round((double)SK.Last().Mad!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Mad!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -87,7 +86,7 @@ public class Skender_Stock
MAPE_Series QL = new(this.bars.Close, this.period, false); MAPE_Series QL = new(this.bars.Close, this.period, false);
var SK = this.quotes.GetSmaAnalysis(this.period); var SK = this.quotes.GetSmaAnalysis(this.period);
Assert.Equal(Math.Round((double)SK.Last().Mape!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Mape!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -96,7 +95,18 @@ public class Skender_Stock
ATR_Series QL = new(this.bars, this.period, false); ATR_Series QL = new(this.bars, this.period, false);
var SK = this.quotes.GetAtr(this.period); var SK = this.quotes.GetAtr(this.period);
Assert.Equal(Math.Round((double)SK.Last().Atr!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Atr!, 6), Math.Round(QL.Last().v, 6));
}
[Fact]
public void OBV()
{
OBV_Series QL = new(this.bars, this.period, false);
var SK = this.quotes.GetObv(this.period);
// adding volume[0] to OBV to pass the test and keep compatibility with TA-LIB
Assert.Equal(Math.Round((double)SK.Last().Obv!, 6) + Math.Round((double)this.quotes.First().Volume!, 6),
Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -105,7 +115,7 @@ public class Skender_Stock
ADL_Series QL = new(this.bars, false); ADL_Series QL = new(this.bars, false);
var SK = this.quotes.GetAdl(); var SK = this.quotes.GetAdl();
Assert.Equal(Math.Round((double)SK.Last().Adl!, 6), Math.Round(QL.Last().v, 6)); Assert.Equal(Math.Round((double)SK.Last().Adl!, 5), Math.Round(QL.Last().v, 5));
} }
[Fact] [Fact]
@@ -114,7 +124,7 @@ public class Skender_Stock
CCI_Series QL = new(this.bars, this.period, false); CCI_Series QL = new(this.bars, this.period, false);
var SK = this.quotes.GetCci(this.period); var SK = this.quotes.GetCci(this.period);
Assert.Equal(Math.Round((double)SK.Last().Cci!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Cci!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -123,7 +133,7 @@ public class Skender_Stock
ATRP_Series QL = new(this.bars, this.period, false); ATRP_Series QL = new(this.bars, this.period, false);
var SK = this.quotes.GetAtr(this.period); var SK = this.quotes.GetAtr(this.period);
Assert.Equal(Math.Round((double)SK.Last().Atrp!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Atrp!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -132,7 +142,7 @@ public class Skender_Stock
KAMA_Series QL = new(this.bars.Close, this.period, useNaN: false); KAMA_Series QL = new(this.bars.Close, this.period, useNaN: false);
var SK = this.quotes.GetKama(this.period); var SK = this.quotes.GetKama(this.period);
Assert.Equal(Math.Round((double)SK.Last().Kama!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Kama!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -141,7 +151,7 @@ public class Skender_Stock
HMA_Series QL = new(this.bars.Close, this.period, useNaN: false); HMA_Series QL = new(this.bars.Close, this.period, useNaN: false);
var SK = this.quotes.GetHma(this.period); var SK = this.quotes.GetHma(this.period);
Assert.Equal(Math.Round((double)SK.Last().Hma!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Hma!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -150,7 +160,7 @@ public class Skender_Stock
SMMA_Series QL = new(this.bars.Close, this.period, useNaN: false); SMMA_Series QL = new(this.bars.Close, this.period, useNaN: false);
var SK = this.quotes.GetSmma(this.period); var SK = this.quotes.GetSmma(this.period);
Assert.Equal(Math.Round((double)SK.Last().Smma!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Smma!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -159,8 +169,8 @@ public class Skender_Stock
MACD_Series QL = new(this.bars.Close, 26,12,9, useNaN: false); MACD_Series QL = new(this.bars.Close, 26,12,9, useNaN: false);
var SK = this.quotes.GetMacd(12,26,9); var SK = this.quotes.GetMacd(12,26,9);
Assert.Equal(Math.Round((double)SK.Last().Macd!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Macd!, 6), Math.Round(QL.Last().v, 6));
Assert.Equal(Math.Round((double)SK.Last().Signal!, 8), Math.Round(QL.Signal.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Signal!, 6), Math.Round(QL.Signal.Last().v, 6));
} }
[Fact] [Fact]
@@ -169,22 +179,21 @@ public class Skender_Stock
BBANDS_Series QL = new(this.bars.Close, this.period, 2.0, useNaN: false); BBANDS_Series QL = new(this.bars.Close, this.period, 2.0, useNaN: false);
var SK = this.quotes.GetBollingerBands(this.period, 2.0); var SK = this.quotes.GetBollingerBands(this.period, 2.0);
Assert.Equal(Math.Round((double)SK.Last().Sma!, 8), Math.Round(QL.Mid.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Sma!, 6), Math.Round(QL.Mid.Last().v, 6));
Assert.Equal(Math.Round((double)SK.Last().UpperBand!, 8), Math.Round(QL.Upper.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().UpperBand!, 6), Math.Round(QL.Upper.Last().v, 6));
Assert.Equal(Math.Round((double)SK.Last().LowerBand!, 8), Math.Round(QL.Lower.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().LowerBand!, 6), Math.Round(QL.Lower.Last().v, 6));
Assert.Equal(Math.Round((double)SK.Last().Width!, 8), Math.Round(QL.Bandwidth.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Width!, 6), Math.Round(QL.Bandwidth.Last().v, 6));
Assert.Equal(Math.Round((double)SK.Last().PercentB!, 8), Math.Round(QL.PercentB.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().PercentB!, 6), Math.Round(QL.PercentB.Last().v, 6));
Assert.Equal(Math.Round((double)SK.Last().ZScore!, 8), Math.Round(QL.Zscore.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().ZScore!, 6), Math.Round(QL.Zscore.Last().v, 6));
} }
[Fact] [Fact]
public void RSI() public void RSI()
{ {
RSI_Series QL = new(this.bars.Close, this.period, useNaN: false); RSI_Series QL = new(this.bars.Close, this.period, useNaN: false);
var SK = this.quotes.GetRsi(this.period); var SK = this.quotes.GetRsi(this.period);
Assert.Equal(Math.Round((double)SK.Last().Rsi!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Rsi!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -193,7 +202,7 @@ public class Skender_Stock
ALMA_Series QL = new(this.bars.Close, this.period, useNaN: false); ALMA_Series QL = new(this.bars.Close, this.period, useNaN: false);
var SK = this.quotes.GetAlma(this.period); var SK = this.quotes.GetAlma(this.period);
Assert.Equal(Math.Round((double)SK.Last().Alma!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Alma!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -202,7 +211,7 @@ public class Skender_Stock
SDEV_Series QL = new(this.bars.Close, this.period, useNaN: false); SDEV_Series QL = new(this.bars.Close, this.period, useNaN: false);
var SK = this.quotes.GetStdDev(this.period); var SK = this.quotes.GetStdDev(this.period);
Assert.Equal(Math.Round((double)SK.Last().StdDev!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -211,10 +220,10 @@ public class Skender_Stock
LINREG_Series QL = new(this.bars.Close, this.period, useNaN: false); LINREG_Series QL = new(this.bars.Close, this.period, useNaN: false);
var SK = this.quotes.GetSlope(this.period); var SK = this.quotes.GetSlope(this.period);
Assert.Equal(Math.Round((double)SK.Last().Slope!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Slope!, 6), Math.Round(QL.Last().v, 6));
Assert.Equal(Math.Round((double)SK.Last().Intercept!, 8), Math.Round(QL.Intercept.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Intercept!, 6), Math.Round(QL.Intercept.Last().v, 6));
Assert.Equal(Math.Round((double)SK.Last().RSquared!, 8), Math.Round(QL.RSquared.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().RSquared!, 6), Math.Round(QL.RSquared.Last().v, 6));
Assert.Equal(Math.Round((double)SK.Last().StdDev!, 8), Math.Round(QL.StdDev.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.StdDev.Last().v, 6));
} }
[Fact] [Fact]
@@ -223,7 +232,7 @@ public class Skender_Stock
TR_Series QL = new(this.bars, useNaN: false); TR_Series QL = new(this.bars, useNaN: false);
var SK = this.quotes.GetTr(); var SK = this.quotes.GetTr();
Assert.Equal(Math.Round((double)SK.Last().Tr!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Tr!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -232,7 +241,7 @@ public class Skender_Stock
TSeries QL = this.bars.HL2; TSeries QL = this.bars.HL2;
var SK = this.quotes.GetBaseQuote(CandlePart.HL2); var SK = this.quotes.GetBaseQuote(CandlePart.HL2);
Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -241,7 +250,7 @@ public class Skender_Stock
TSeries QL = this.bars.OC2; TSeries QL = this.bars.OC2;
var SK = this.quotes.GetBaseQuote(CandlePart.OC2); var SK = this.quotes.GetBaseQuote(CandlePart.OC2);
Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -250,7 +259,7 @@ public class Skender_Stock
TSeries QL = this.bars.HLC3; TSeries QL = this.bars.HLC3;
var SK = this.quotes.GetBaseQuote(CandlePart.HLC3); var SK = this.quotes.GetBaseQuote(CandlePart.HLC3);
Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -259,7 +268,7 @@ public class Skender_Stock
TSeries QL = this.bars.OHL3; TSeries QL = this.bars.OHL3;
var SK = this.quotes.GetBaseQuote(CandlePart.OHL3); var SK = this.quotes.GetBaseQuote(CandlePart.OHL3);
Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
} }
[Fact] [Fact]
@@ -268,6 +277,6 @@ public class Skender_Stock
TSeries QL = this.bars.OHLC4; TSeries QL = this.bars.OHLC4;
var SK = this.quotes.GetBaseQuote(CandlePart.OHLC4); var SK = this.quotes.GetBaseQuote(CandlePart.OHLC4);
Assert.Equal(Math.Round((double)SK.Last().Value!, 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6));
} }
} }
+47 -34
View File
@@ -18,7 +18,7 @@ public class TA_LIB
public TA_LIB() public TA_LIB()
{ {
this.bars = new(1000); this.bars = new(5000);
this.period = this.rnd.Next(28) + 3; this.period = this.rnd.Next(28) + 3;
this.TALIB = new double[this.bars.Count]; this.TALIB = new double[this.bars.Count];
this.inopen = this.bars.Open.v.ToArray(); this.inopen = this.bars.Open.v.ToArray();
@@ -36,7 +36,7 @@ public class TA_LIB
ADD_Series QL = new(this.bars.Open, this.bars.Close); ADD_Series QL = new(this.bars.Open, this.bars.Close);
Core.Add(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); Core.Add(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -45,7 +45,7 @@ public class TA_LIB
SUB_Series QL = new(this.bars.Open, this.bars.Close); SUB_Series QL = new(this.bars.Open, this.bars.Close);
Core.Sub(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); Core.Sub(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -54,7 +54,7 @@ public class TA_LIB
MUL_Series QL = new(this.bars.Open, this.bars.Close); MUL_Series QL = new(this.bars.Open, this.bars.Close);
Core.Mult(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); Core.Mult(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -63,7 +63,7 @@ public class TA_LIB
DIV_Series QL = new(this.bars.Open, this.bars.Close); DIV_Series QL = new(this.bars.Open, this.bars.Close);
Core.Div(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); Core.Div(this.inopen, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -72,17 +72,25 @@ public class TA_LIB
SDEV_Series QL = new(this.bars.Close, this.period, false); SDEV_Series QL = new(this.bars.Close, this.period, false);
Core.StdDev(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); Core.StdDev(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void SMA() public void SMA()
{ {
SMA_Series QL = new(this.bars.Close, this.period, false); SMA_Series QL = new(this.bars.Close, this.period, false);
Core.Sma(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); Core.Sma(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
}
[Fact]
public void TRIMA()
{
TRIMA_Series QL = new(this.bars.Close, this.period, false);
Core.Trima(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -91,7 +99,7 @@ public class TA_LIB
EMA_Series QL = new(this.bars.Close, this.period, false); EMA_Series QL = new(this.bars.Close, this.period, false);
Core.Ema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); Core.Ema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -99,8 +107,8 @@ public class TA_LIB
{ {
WMA_Series QL = new(this.bars.Close, this.period, false); WMA_Series QL = new(this.bars.Close, this.period, false);
Core.Wma(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); Core.Wma(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -109,7 +117,7 @@ public class TA_LIB
DEMA_Series QL = new(this.bars.Close, this.period, false); DEMA_Series QL = new(this.bars.Close, this.period, false);
Core.Dema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); Core.Dema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -118,7 +126,7 @@ public class TA_LIB
TEMA_Series QL = new(this.bars.Close, this.period, false); TEMA_Series QL = new(this.bars.Close, this.period, false);
Core.Tema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); Core.Tema(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -127,7 +135,7 @@ public class TA_LIB
MAX_Series QL = new(this.bars.Close, this.period, false); MAX_Series QL = new(this.bars.Close, this.period, false);
Core.Max(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); Core.Max(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -136,7 +144,7 @@ public class TA_LIB
MIN_Series QL = new(this.bars.Close, this.period, false); MIN_Series QL = new(this.bars.Close, this.period, false);
Core.Min(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); Core.Min(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -145,7 +153,16 @@ public class TA_LIB
ADL_Series QL = new(this.bars, false); ADL_Series QL = new(this.bars, false);
Core.Ad(this.inhigh, this.inlow, this.inclose, this.involume, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); Core.Ad(this.inhigh, this.inlow, this.inclose, this.involume, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
}
[Fact]
public void OBV()
{
OBV_Series QL = new(this.bars, this.period, false);
Core.Obv(this.inclose, this.involume, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -154,7 +171,7 @@ public class TA_LIB
ADOSC_Series QL = new(this.bars, false); ADOSC_Series QL = new(this.bars, false);
Core.AdOsc(this.inhigh, this.inlow, this.inclose, this.involume, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); Core.AdOsc(this.inhigh, this.inlow, this.inclose, this.involume, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -163,7 +180,7 @@ public class TA_LIB
ATR_Series QL = new(this.bars, this.period, false); ATR_Series QL = new(this.bars, this.period, false);
Core.Atr(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); Core.Atr(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -172,7 +189,7 @@ public class TA_LIB
CCI_Series QL = new(this.bars, this.period, false); CCI_Series QL = new(this.bars, this.period, false);
Core.Cci(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); Core.Cci(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -181,7 +198,7 @@ public class TA_LIB
RSI_Series QL = new(this.bars.Close, this.period, false); RSI_Series QL = new(this.bars.Close, this.period, false);
Core.Rsi(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period); Core.Rsi(this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _, this.period);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -190,7 +207,7 @@ public class TA_LIB
TR_Series QL = new(this.bars, false); TR_Series QL = new(this.bars, false);
Core.TRange(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); Core.TRange(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -200,8 +217,8 @@ public class TA_LIB
double[] macdHist = new double[this.bars.Count]; double[] macdHist = new double[this.bars.Count];
MACD_Series QL = new(this.bars.Close, slow: 26, fast: 12, signal: 9, false); MACD_Series QL = new(this.bars.Close, slow: 26, fast: 12, signal: 9, false);
Core.Macd(this.inclose, 0, this.bars.Count - 1, outMacd: this.TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _); Core.Macd(this.inclose, 0, this.bars.Count - 1, outMacd: this.TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
Assert.Equal(Math.Round(macdSignal[macdSignal.Length - outBegIdx - 1], 8), Math.Round(QL.Signal.Last().v, 8)); Assert.Equal(Math.Round(macdSignal[macdSignal.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Signal.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -212,21 +229,18 @@ public class TA_LIB
double[] outLower = new double[this.bars.Count]; double[] outLower = new double[this.bars.Count];
BBANDS_Series QL = new(this.bars.Close, period:26, multiplier:2.0, false); BBANDS_Series QL = new(this.bars.Close, period:26, multiplier:2.0, false);
Core.Bbands(this.inclose, 0, this.bars.Count - 1, outRealUpperBand: outUpper, outRealMiddleBand: outMiddle, outRealLowerBand: outLower, out int outBegIdx, out _, optInTimePeriod:26, optInNbDevUp:2.0, optInNbDevDn:2.0); Core.Bbands(this.inclose, 0, this.bars.Count - 1, outRealUpperBand: outUpper, outRealMiddleBand: outMiddle, outRealLowerBand: outLower, out int outBegIdx, out _, optInTimePeriod:26, optInNbDevUp:2.0, optInNbDevDn:2.0);
Assert.Equal(Math.Round(outUpper[outUpper.Length - outBegIdx - 1], 7), Math.Round(QL.Upper.Last().v, 7)); Assert.Equal(Math.Round(outUpper[outUpper.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Upper.Last().v, 6, MidpointRounding.AwayFromZero));
Assert.Equal(Math.Round(outMiddle[outMiddle.Length - outBegIdx - 1], 7), Math.Round(QL.Mid.Last().v, 7)); Assert.Equal(Math.Round(outMiddle[outMiddle.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Mid.Last().v, 6, MidpointRounding.AwayFromZero));
Assert.Equal(Math.Round(outLower[outLower.Length - outBegIdx - 1], 7), Math.Round(QL.Lower.Last().v, 7)); Assert.Equal(Math.Round(outLower[outLower.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Lower.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
public void HL2() public void HL2()
{ {
TSeries QL = this.bars.HL2; TSeries QL = this.bars.HL2;
Core.MedPrice(this.inhigh, this.inlow, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); Core.MedPrice(this.inhigh, this.inlow, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -235,7 +249,7 @@ public class TA_LIB
TSeries QL = this.bars.HLC3; TSeries QL = this.bars.HLC3;
Core.TypPrice(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); Core.TypPrice(this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -244,7 +258,7 @@ public class TA_LIB
TSeries QL = this.bars.OHLC4; TSeries QL = this.bars.OHLC4;
Core.AvgPrice(this.inopen, this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); Core.AvgPrice(this.inopen, this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
[Fact] [Fact]
@@ -253,7 +267,6 @@ public class TA_LIB
TSeries QL = this.bars.HLCC4; TSeries QL = this.bars.HLCC4;
Core.WclPrice( this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _); Core.WclPrice( this.inhigh, this.inlow, this.inclose, 0, this.bars.Count - 1, this.TALIB, out int outBegIdx, out _);
Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 8), Math.Round(QL.Last().v, 8)); Assert.Equal(Math.Round(this.TALIB[this.TALIB.Length - outBegIdx - 1], 6, MidpointRounding.AwayFromZero), Math.Round(QL.Last().v, 6, MidpointRounding.AwayFromZero));
} }
} }
+12 -21
View File
File diff suppressed because one or more lines are too long
+73 -74
View File
@@ -37,84 +37,91 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
| **BASIC TRANSFORMS** | **QuanTAlib** | **TA-LIB** | **Skender** | | **BASIC TRANSFORMS** | **QuanTAlib** | **TA-LIB** | **Skender** |
|--|:--:|:--:|:--:| |--|:--:|:--:|:--:|
| ✔️ OC2 - (Open+Close)/2 | `.OC2` || `GetBaseQuote` | | ✔️ OC2 - (Open+Close)/2 | `.OC2` || GetBaseQuote |
| ⭐ HL2 - Median Price | `.HL2` | `MEDPRICE` | `GetBaseQuote` | | ⭐ HL2 - Median Price | `.HL2` | MEDPRICE | GetBaseQuote |
| ⭐ HLC3 - Typical Price | `.HLC3` | `TYPPRICE` || | ⭐ HLC3 - Typical Price | `.HLC3` | TYPPRICE ||
| ✔️ OHL3 - (Open+High+Low)/3 | `.OHL3` ||| | ✔️ OHL3 - (Open+High+Low)/3 | `.OHL3` |||
| ⭐ OHLC4 - Average Price | `.OHLC4` | `AVGPRICE` | `GetBaseQuote` | | ⭐ OHLC4 - Average Price | `.OHLC4` | AVGPRICE | GetBaseQuote |
| ⭐ HLCC4 - Weighted Price | `.HLCC4` | `WCLPRICE` || | ⭐ HLCC4 - Weighted Price | `.HLCC4` | WCLPRICE ||
| ✔️ ZL - De-lagged price (Zero-Lag) | `ZL_Series` ||| | ⭐ MAX - Max value | `MAX_Series` | MAX ||
| ⭐ MAX - Max value | `MAX_Series` | `MAX` || | ⭐ MIN - Min value | `MIN_Series` | MIN ||
| ⛔ MID - Midpoint value || `MIDPOINT` || | ⛔ MID - Midpoint value || MIDPOINT ||
| ⛔ MIDP - Midpoint price || `MIDPRICE` || | ⛔ MIDP - Midpoint price || MIDPRICE ||
| ⭐ MIN - Min value | `MIN_Series` | `MIN` || | ⛔ SUM - Summation || SUM ||
| ⭐ ADD - Addition | `ADD_Series` | `ADD` || | ⭐ ADD - Addition | `ADD_Series` | ADD ||
| ⭐ SUB - Subtraction | `SUB_Series` | `SUB` || | ⭐ SUB - Subtraction | `SUB_Series` | SUB ||
| ⭐ MUL - Multiplication | `MUL_Series` | `MUL` || | ⭐ MUL - Multiplication | `MUL_Series` | MUL ||
| ⭐ DIV - Division | `DIV_Series` | `DIV` || | ⭐ DIV - Division | `DIV_Series` | DIV ||
||||| |||||
| **STATISTICS & NUMERICAL ANALYSIS** | **QuanTAlib** | **TA-LIB** | **Skender** | | **STATISTICS & NUMERICAL ANALYSIS** | **QuanTAlib** | **TA-LIB** | **Skender** |
| ✔️ BIAS - Bias | BIAS_Series ||| | ✔️ BIAS - Bias | `BIAS_Series` |||
| ⛔ CORREL - Pearson's Correlation Coefficient || CORREL | GetCorrelation | | ⛔ CORREL - Pearson's Correlation Coefficient || CORREL | GetCorrelation |
| ⛔ COVAR - Covariance ||| GetCorrelation | | ⛔ COVAR - Covariance ||| GetCorrelation |
| ✔️ ENTP - Entropy | ENTP_Series ||| | ✔️ ENTP - Entropy | `ENTP_Series` |||
| ✔️ KURT - Kurtosis | KURT_Series ||| | ✔️ KURT - Kurtosis | `KURT_Series` |||
| ⭐ LINREG - Linear Regression | LINREG_Series || GetSlope | | ⭐ LINREG - Linear Regression | `LINREG_Series` || GetSlope |
| ⭐ MAD - Mean Absolute Deviation | MAD_Series || GetSma | | ⭐ MAD - Mean Absolute Deviation | `MAD_Series` || GetSma |
| ⭐ MAPE - Mean Absolute Percent Error | MAPE_Series || GetSma | | ⭐ MAPE - Mean Absolute Percent Error | `MAPE_Series` || GetSma |
| ✔️ MED - Median value | MED_Series ||| | ✔️ MED - Median value | `MED_Series` |||
| ✔️ MSE - Mean Squared Error | MSE_Series || GetSma | | ✔️ MSE - Mean Squared Error | `MSE_Series` || GetSma |
| ⛔ SKEW - Skewness |||| | ⛔ SKEW - Skewness ||||
| ⭐ SDEV - Standard Deviation (Volatility) | SDEV_Series ||| | ⭐ SDEV - Standard Deviation (Volatility) | `SDEV_Series` | STDDEV ||
| ✔️ SSDEV - Sample Standard Deviation | SSDEV_Series ||| | ✔️ SSDEV - Sample Standard Deviation | `SSDEV_Series` |||
| ✔️ SMAPE - Symmetric Mean Absolute Percent Error | SMAPE_Series ||| | ✔️ SMAPE - Symmetric Mean Absolute Percent Error | `SMAPE_Series` |||
| ✔️ VAR - Population Variance | VAR_Series ||| | ✔️ VAR - Population Variance | `VAR_Series` | VAR ||
| ✔️ SVAR - Sample Variance | SVAR_Series ||| | ✔️ SVAR - Sample Variance | `SVAR_Series` |||
| ⛔ QUANT - Quantile |||| | ⛔ QUANT - Quantile ||||
| ✔️ WMAPE - Weighted Mean Absolute Percent Error | WMAPE_Series ||| | ✔️ WMAPE - Weighted Mean Absolute Percent Error | `WMAPE_Series` |||
| ⛔ ZSCORE - Number of standard deviations from mean |||| | ⛔ ZSCORE - Number of standard deviations from mean ||||
||||| |||||
| **TREND INDICATORS & AVERAGES** | **QuanTAlib** | **TA-LIB** | **Skender** | | **TREND INDICATORS & AVERAGES** | **QuanTAlib** | **TA-LIB** | **Skender** |
| ⛔ AFIRMA - Autoregressive Finite Impulse Response Moving Average |||| | ⛔ AFIRMA - Autoregressive Finite Impulse Response Moving Average ||||
| ⭐ ALMA - Arnaud Legoux Moving Average | ALMA_Series || GetAlma | | ⭐ ALMA - Arnaud Legoux Moving Average | `ALMA_Series` || GetAlma |
| ⛔ ARIMA - Autoregressive Integrated Moving Average |||| | ⛔ ARIMA - Autoregressive Integrated Moving Average ||||
| ⭐ DEMA - Double EMA Average | DEMA_Series | DEMA | GetDema | | ⭐ DEMA - Double EMA Average | `DEMA_Series` | DEMA | GetDema |
| ⭐ EMA - Exponential Moving Average | EMA_Series || GetEma | | ⭐ EMA - Exponential Moving Average | `EMA_Series` || GetEma |
| ⛔ EPMA - Endpoint Moving Average ||| GetEpma | | ⛔ EPMA - Endpoint Moving Average ||| GetEpma |
| ⛔ FRAMA - Fractal Adaptive Moving Average ||||
| ⛔ FWMA - Fibonacci's Weighted Moving Average |||| | ⛔ FWMA - Fibonacci's Weighted Moving Average ||||
| ✔️ HEMA - Hull/EMA Average | HEMA_Series ||| | ⛔ HILO - Gann High-Low Activator ||||
| ✔️ HEMA - Hull/EMA Average | `HEMA_Series` |||
| ⛔ Hilbert Transform Instantaneous Trendline || HT_TRENDLINE | GetHtTrendline | | ⛔ Hilbert Transform Instantaneous Trendline || HT_TRENDLINE | GetHtTrendline |
| ⭐ HMA - Hull Moving Average | HMA_Series || GetHma | | ⭐ HMA - Hull Moving Average | `HMA_Series` || GetHma |
| ⛔ HWMA - Holt-Winter Moving Average |||| | ⛔ HWMA - Holt-Winter Moving Average ||||
| ✔️ JMA - Jurik Moving Average | JMA_Series ||| | ✔️ JMA - Jurik Moving Average | `JMA_Series` |||
| ⭐ KAMA - Kaufman's Adaptive Moving Average | KAMA_Series | KAMA | GetKama | | ⭐ KAMA - Kaufman's Adaptive Moving Average | `KAMA_Series` | KAMA | GetKama |
| ⛔ KDJ - KDJ Indicator (trend reversal) ||||
| ⛔ LSMA - Least Squares Moving Average |||| | ⛔ LSMA - Least Squares Moving Average ||||
| ⭐ MACD - Moving Average Convergence/Divergence | MACD_Series | MACD | GetMacd | | ⭐ MACD - Moving Average Convergence/Divergence | `MACD_Series` | MACD | GetMacd |
| ⛔ MAMA - MESA Adaptive Moving Average || MAMA | GetMama | | ⛔ MAMA - MESA Adaptive Moving Average || MAMA | GetMama |
| ⛔ MCGD - McGinley Dynamic ||||
| ⛔ MMA - Modified Moving Average |||| | ⛔ MMA - Modified Moving Average ||||
| ⛔ PPMA - Pivot Point Moving Average |||| | ⛔ PPMA - Pivot Point Moving Average ||||
| ⛔ PWMA - Pascal's Weighted Moving Average |||| | ⛔ PWMA - Pascal's Weighted Moving Average ||||
| ✔️ RMA - WildeR's Moving Average | RMA__Series ||| | ✔️ RMA - WildeR's Moving Average | `RMA_Series` |||
| ⛔ SINWMA - Sine Weighted Moving Average |||| | ⛔ SINWMA - Sine Weighted Moving Average ||||
| ⭐ SMA - Simple Moving Average | SMA_Series ||| | ⭐ SMA - Simple Moving Average | `SMA_Series` | SMA | GetSma |
| ⭐ SMMA - Smoothed Moving Average | SMMA_Series ||| | ⭐ SMMA - Smoothed Moving Average | `SMMA_Series` |||
| ⛔ SSF - Ehler's Super Smoother Filter |||| | ⛔ SSF - Ehler's Super Smoother Filter ||||
| ⛔ SUP - Supertrend |||| | ⛔ SUP - Supertrend ||||
| ⛔ SWMA - Symmetric Weighted Moving Average |||| | ⛔ SWMA - Symmetric Weighted Moving Average ||||
| ⛔ T3 - Tillson T3 Moving Average |||| | ⛔ T3 - Tillson T3 Moving Average || T3 | GetT3 |
| ⭐ TEMA - Triple EMA Average | TEMA_Series ||| | ⭐ TEMA - Triple EMA Average | `TEMA_Series` | TEMA | GetTema |
| TRIMA - Triangular Moving Average |||| | TRIMA - Triangular Moving Average | `TRIMA_Series` | TRIMA ||
| ⛔ TSF - Time Series Forecast || TSF ||
| ⛔ VIDYA - Variable Index Dynamic Average |||| | ⛔ VIDYA - Variable Index Dynamic Average ||||
| ⭐ WMA - Weighted Moving Average | WMA_Series ||| | ⛔ VOR - Vortex Indicator ||||
| ✔️ ZLEMA - Zero Lag EMA Average | ZLEMA_Series ||| | ⭐ WMA - Weighted Moving Average | `WMA_Series` | WMA | GetWma |
| ✔️ ZLEMA - Zero Lag EMA Average | `ZLEMA_Series` |||
||||| |||||
| **VOLATILITY INDICATORS** | **QuanTAlib** | **TA-LIB** | **Skender** | | **VOLATILITY INDICATORS** | **QuanTAlib** | **TA-LIB** | **Skender** |
| ⭐ ADL - Chaikin Accumulation Distribution Line | ADL_Series | AD | GetAdl | | ⭐ ADL - Chaikin Accumulation Distribution Line | `ADL_Series` | AD | GetAdl |
| ⭐ ADOSC - Chaikin Accumulation Distribution Oscillator | ADOSC_Series | ADOSC| GetAdl | | ⭐ ADOSC - Chaikin Accumulation Distribution Oscillator | `ADOSC_Series` | ADOSC| GetAdl |
| ⭐ ATR - Average True Range | ATR_Series | ATR | GetAtr | | ⭐ ATR - Average True Range | `ATR_Series` | ATR | GetAtr |
| ⭐ ATRP - Average True Range Percent | ATRP_Series || GetAtr | | ⭐ ATRP - Average True Range Percent | `ATRP_Series` || GetAtr |
| ✔️ BETA - Beta coefficient || BETA | GetBeta | | BETA - Beta coefficient || BETA | GetBeta |
| ⭐ BBANDS - Bollinger Bands® | BBANDS_Series | BBANDS | GetBollingerBands | | ⭐ BBANDS - Bollinger Bands® | `BBANDS_Series` | BBANDS | GetBollingerBands |
| ⛔ CHAND - Chandelier Exit ||| GetChandelier |
| ⛔ CRSI - Connor RSI ||| GetConnorsRsi | | ⛔ CRSI - Connor RSI ||| GetConnorsRsi |
| ⛔ DON - Donchian Channels ||| GetDonchian | | ⛔ DON - Donchian Channels ||| GetDonchian |
| ⛔ FCB - Fractal Chaos Bands ||| GetFcb | | ⛔ FCB - Fractal Chaos Bands ||| GetFcb |
@@ -122,11 +129,12 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
| ⛔ ICH - Ichimoku ||| GetIchimoku | | ⛔ ICH - Ichimoku ||| GetIchimoku |
| ⛔ KEL - Keltner Channels ||| GetKeltner | | ⛔ KEL - Keltner Channels ||| GetKeltner |
| ⛔ NATR - Normalized Average True Range || NATR | GetAtr | | ⛔ NATR - Normalized Average True Range || NATR | GetAtr |
| ⭐ RSI - Relative Strength Index | RSI_Series || | ⛔ CHN - Price Channel Indicator ||||
| ⭐ RSI - Relative Strength Index | `RSI_Series` | RSI | GetRsi |
| ⛔ SAR - Parabolic Stop and Reverse || SAR | GetParabolicSar | | ⛔ SAR - Parabolic Stop and Reverse || SAR | GetParabolicSar |
| ⛔ SRSI - Stochastic RSI |||| | ⛔ SRSI - Stochastic RSI || STOCHRSI | GetStochRsi |
| ⛔ STARC - Starc Bands |||| | ⛔ STARC - Starc Bands ||||
| ⭐ TR - True Range | TR_Series ||| | ⭐ TR - True Range | `TR_Series` | TRANGE | GetTr |
| ⛔ UI - Ulcer Index |||| | ⛔ UI - Ulcer Index ||||
| ⛔ VSTOP - Volatility Stop |||| | ⛔ VSTOP - Volatility Stop ||||
||||| |||||
@@ -138,11 +146,11 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
| ⛔ APO - Absolute Price Oscillator || APO || | ⛔ APO - Absolute Price Oscillator || APO ||
| ⛔ AROON - Aroon oscillator || AROON | GetAroon | | ⛔ AROON - Aroon oscillator || AROON | GetAroon |
| ⛔ BOP - Balance of Power || BOP | GetBop | | ⛔ BOP - Balance of Power || BOP | GetBop |
| ⭐ CCI - Commodity Channel Index | CCI_Series | CCI | GetCci | | ⭐ CCI - Commodity Channel Index | `CCI_Series` | CCI | GetCci |
| ⛔ CFO - Chande Forcast Oscillator |||| | ⛔ CFO - Chande Forcast Oscillator ||||
| ⛔ CMF - Chaikin Money Flow ||||
| ⛔ CMO - Chande Momentum Oscillator || CMO | GetCmo | | ⛔ CMO - Chande Momentum Oscillator || CMO | GetCmo |
| ⛔ COG - Center of Gravity |||| | ⛔ COG - Center of Gravity ||||
| ⛔ COPPOCK - Coppock Curve ||||
| ⛔ CTI - Ehler's Correlation Trend Indicator |||| | ⛔ CTI - Ehler's Correlation Trend Indicator ||||
| ⛔ DPO - Detrended Price Oscillator ||| GetDpo | | ⛔ DPO - Detrended Price Oscillator ||| GetDpo |
| ⛔ DMI - Directional Movement Index || DX | GetAdx | | ⛔ DMI - Directional Movement Index || DX | GetAdx |
@@ -152,23 +160,28 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
| ⛔ KRI - Kairi Relative Index |||| | ⛔ KRI - Kairi Relative Index ||||
| ⛔ KVO - Klinger Volume Oscillator |||| | ⛔ KVO - Klinger Volume Oscillator ||||
| ⛔ MFI - Money Flow Index || MFI | GetMfi | | ⛔ MFI - Money Flow Index || MFI | GetMfi |
| ⛔ ROC - Rate of Change (Momentum) || MOM | GetRoc | | ⛔ MOM - Momentum || MOM ||
| ⛔ NVI - Negative Volume Index |||| | ⛔ NVI - Negative Volume Index ||||
| ⛔ PO - Price Oscillator |||| | ⛔ PO - Price Oscillator ||||
| ⛔ PPO - Percentage Price Oscillator || PPO || | ⛔ PPO - Percentage Price Oscillator || PPO ||
| ⛔ PMO - Price Momentum Oscillator |||| | ⛔ PMO - Price Momentum Oscillator ||||
| ⛔ PVI - Positive Volume Index |||| | ⛔ PVI - Positive Volume Index ||||
| ⛔ ROC - Rate of Change || MOM | GetRoc |
| ⛔ RVGI - Relative Vigor Index |||| | ⛔ RVGI - Relative Vigor Index ||||
| ⛔ SMI - Stochastic Momentum Index |||| | ⛔ SMI - Stochastic Momentum Index ||||
| ⛔ STOCH - Stochastic Oscillator |||| | ⛔ STC - Schaff Trend Cycle ||||
| ⛔ TRIX - 1-day ROC of TEMA |||| | ⛔ STOCH - Stochastic Oscillator || STOCH | GetStoch |
| ⛔ TRIX - 1-day ROC of TEMA || TRIX | GetTrix |
| ⛔ TSI - True Strength Index |||| | ⛔ TSI - True Strength Index ||||
| ⛔ UO - Ultimate Oscillator |||| | ⛔ UO - Ultimate Oscillator || ULTOSC | GetUltimate |
| ⛔ WILLR - Larry Williams' %R || WILLR | GetWilliamsR |
| ⛔ WGAT - Williams Alligator |||| | ⛔ WGAT - Williams Alligator ||||
||||| |||||
| **VOLUME INDICATORS** | **QuanTAlib** | **TA-LIB** | **Skender** | | **VOLUME INDICATORS** | **QuanTAlib** | **TA-LIB** | **Skender** |
| ⛔ AOBV - Archer On-Balance Volume |||| | ⛔ AOBV - Archer On-Balance Volume ||||
| ⛔ OBV - On-Balance Volume || OBV | GetObv | | ⛔ CMF - Chaikin Money Flow ||||
| ⛔ EOM - Ease of Movement ||||
| ⭐ OBV - On-Balance Volume | `OBV_Series` | OBV | GetObv |
| ⛔ PRS - Price Relative Strength ||| | ⛔ PRS - Price Relative Strength |||
| ⛔ PVOL - Price-Volume |||| | ⛔ PVOL - Price-Volume ||||
| ⛔ PVO - Percentage Volume Oscillator |||| | ⛔ PVO - Percentage Volume Oscillator ||||
@@ -177,17 +190,3 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
| ⛔ VP - Volume Profile |||| | ⛔ VP - Volume Profile ||||
| ⛔ VWAP - Volume Weighted Average Price |||| | ⛔ VWAP - Volume Weighted Average Price ||||
| ⛔ VWMA - Volume Weighted Moving Average |||| | ⛔ VWMA - Volume Weighted Moving Average ||||
|||||
|**Unsorted** | **QuanTAlib** | **TA-LIB** | **Skender** |
| ⛔ CHN - Price Channel ||||
| ⛔ COPPOCK - Coppock Curve ||||
| ⛔ EOM - Ease of Movement ||||
| ⛔ HILO - Gann High-Low Activator ||||
| ⛔ HT - HT Trendline ||||
| ⛔ MCGD - McGinley Dynamic ||||
| ⛔ STC - Schaff Trend Cycle ||||
| ⛔ WILLR - Larry Williams' %R ||||
| ⛔ VOR - Vortex Indicator ||||
| ⛔ PVT - Pivot Points ||||
| ⛔ KDJ - KDJ Index ||||
| ⛔ CHAND - Chandelier Exit ||||