Fixed ATR and ATRP, improved SMA

This commit is contained in:
Miha Kralj
2023-01-03 17:55:41 -08:00
parent 83e5d89cbb
commit 5d72f9d3ae
8 changed files with 135 additions and 129 deletions
+2 -2
View File
@@ -2,9 +2,9 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<Title>QuanTAlib</Title> <Title>QuanTAlib</Title>
<Version>0.1.24</Version> <Version>0.1.25</Version>
<Product>Library of Technical Indicators for .NET</Product> <Product>Library of Technical Indicators for .NET</Product>
<Description>Quantitative Technical Analysis library for both real-time (streaming) and historical data analysis</Description> <Description>Quantitative Technical Analysis library for real-time (streaming) data analysis</Description>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/mihakralj/QuanTAlib</RepositoryUrl> <RepositoryUrl>https://github.com/mihakralj/QuanTAlib</RepositoryUrl>
<PublishRepositoryUrl>true</PublishRepositoryUrl> <PublishRepositoryUrl>true</PublishRepositoryUrl>
+25 -1
View File
@@ -16,6 +16,30 @@ Remark:
</summary> */ </summary> */
public class SMA_Series : Single_TSeries_Indicator {
private double _sum, _oldsum;
private int _len, _oldlen;
public SMA_Series(TSeries source, int period = 0, bool useNaN = false) : base(source, period, false) {
Reset();
if (this._data.Count > 0) { base.Add(this._data); }
}
public override void Add((DateTime t, double v) TValue, bool update) {
if (update) { _sum = _oldsum; }
else { _oldsum = _sum; _len++; }
_sum += TValue.v;
if (_period != 0 && _len > _period)
_sum -= (_data[base.Count - _period - (update ? 1 : 0)].v);
double _div = (_period == 0) ? _len : Math.Min(_len, _period);
base.Add((TValue.t, _sum / _div), update, _NaN);
}
public void Reset() {
_sum = _oldsum = 0;
_len = _oldlen = 0;
}
}
/*
public class SMA_Series : Single_TSeries_Indicator public class SMA_Series : Single_TSeries_Indicator
{ {
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly System.Collections.Generic.List<double> _buffer = new();
@@ -59,4 +83,4 @@ public class SMA_Series : Single_TSeries_Indicator
base.Add((TValue.t, _sma), update, _NaN); base.Add((TValue.t, _sma), update, _NaN);
} }
} }*/
+31 -45
View File
@@ -11,53 +11,39 @@ Sources:
</summary> */ </summary> */
public class ATRP_Series : Single_TBars_Indicator public class ATRP_Series : Single_TBars_Indicator {
{ private readonly System.Collections.Generic.List<double> _buffer = new();
private readonly System.Collections.Generic.List<double> _buffer = new(); private readonly double _k;
private readonly double _k, _k1m; private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
private double _lastema, _lastlastema, _lastcm1; private readonly int _period;
private double _cm1 = double.NaN;
public ATRP_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) public ATRP_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) {
{ _period = period;
this._k = 1.0 / (double)(this._p); _k = 1.0 / (double)(_p);
this._k1m = 1.0 - this._k; _lastatr = _lastlastatr = _cm1 = _lastcm1 = _sum = _oldsum = 0;
this._lastema = this._lastlastema = double.NaN; if (this._bars.Count > 0) { base.Add(this._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) {
{ if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
if (update) { else { _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum; }
this._lastema = this._lastlastema;
this._cm1 = this._lastcm1;
}
if (_cm1 is double.NaN) { _cm1 = TBar.c; } if (this.Count == 0)
double d1 = Math.Abs(TBar.h - TBar.l); _cm1 = TBar.c;
double d2 = Math.Abs(_cm1 - TBar.h); double d1 = Math.Abs(TBar.h - TBar.l);
double d3 = Math.Abs(_cm1 - TBar.l); double d2 = Math.Abs(_cm1 - TBar.h);
(DateTime t, double v)d = (TBar.t, Math.Max(d1,Math.Max(d2,d3))); //TR value for RMA below double d3 = Math.Abs(_cm1 - TBar.l);
_lastcm1 = _cm1; (DateTime t, double v) d = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
_cm1 = TBar.c; _cm1 = TBar.c;
double _ema = 0; double _atr = 0;
if (this.Count < this._p) if (this.Count == 0) { _atr = d.v; }
{ else if (this.Count < _p + 1) { _sum += d.v; _atr = _sum / (this.Count); }
if (update) { _buffer[_buffer.Count - 1] = d.v; } else { _atr = _k * (d.v - _lastatr) + _lastatr; }
else { _buffer.Add(d.v); } _lastatr = _atr;
if (_buffer.Count > this._p) { _buffer.RemoveAt(0); }
for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; }
_ema /= this._buffer.Count;
}
else { _ema = (d.v * _k) + (_lastema * _k1m); }
this._lastlastema = this._lastema; double _atrp = 100 * (_atr / TBar.c);
this._lastema = _ema; var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atrp);
base.Add(ret, update);
double _atrp = 100 * (_ema / TBar.c); }
}
var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atrp);
base.Add(ret, update);
}
}
+29 -42
View File
@@ -13,51 +13,38 @@ 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(); private readonly double _k;
private readonly double _k, _k1m; private double _lastatr, _lastlastatr, _cm1, _lastcm1, _sum, _oldsum;
private double _lastema, _lastlastema, _lastcm1; private readonly int _period;
private double _cm1;
public ATR_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) public ATR_Series(TBars source, int period, bool useNaN = false) : base(source, period, useNaN) {
{ _period = period;
this._k = 1.0 / (double)(this._p); _k = 1.0 / (double)(_p);
this._k1m = 1.0 - this._k; _lastatr = _lastlastatr = _cm1 = _lastcm1 = _sum = _oldsum = 0;
this._lastema = this._lastlastema = double.NaN; if (this._bars.Count > 0) { base.Add(this._bars); }
if (this._bars.Count > 0) { base.Add(this._bars); } }
}
public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) public override void Add((DateTime t, double o, double h, double l, double c, double v) TBar, bool update) {
{ if (update) { _lastatr = _lastlastatr; _cm1 = _lastcm1; _sum = _oldsum; }
if (update) { else { _lastlastatr = _lastatr; _lastcm1 = _cm1; _oldsum = _sum; }
this._lastema = this._lastlastema;
this._cm1 = this._lastcm1;
}
if (this.Count == 0) { this._cm1 = TBar.c; } if (this.Count == 0)
double d1 = Math.Abs(TBar.h - TBar.l); _cm1 = TBar.c;
double d2 = Math.Abs(_cm1 - TBar.h); double d1 = Math.Abs(TBar.h - TBar.l);
double d3 = Math.Abs(_cm1 - TBar.l); double d2 = Math.Abs(_cm1 - TBar.h);
(DateTime t, double v)d = (TBar.t, Math.Max(d1,Math.Max(d2,d3))); double d3 = Math.Abs(_cm1 - TBar.l);
_lastcm1 = _cm1; (DateTime t, double v) d = (TBar.t, Math.Max(d1, Math.Max(d2, d3)));
_cm1 = TBar.c; _cm1 = TBar.c;
double _ema = 0; double _atr = 0;
if (this.Count < this._p) if (this.Count == 0) { _atr = d.v; }
{ else if (this.Count < _p + 1) { _sum += d.v; _atr = _sum / (this.Count); }
if (update) { _buffer[_buffer.Count - 1] = d.v; } else { _atr = _k * (d.v - _lastatr) + _lastatr; }
else { _buffer.Add(d.v); } _lastatr = _atr;
if (_buffer.Count > this._p) { _buffer.RemoveAt(0); }
for (int i = 0; i < _buffer.Count; i++) { _ema += _buffer[i]; }
_ema /= this._buffer.Count;
}
else { _ema = (d.v * _k) + (_lastema * _k1m); }
this._lastlastema = this._lastema; var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _atr);
this._lastema = _ema; base.Add(ret, update);
}
var ret = (d.t, this.Count < this._p - 1 && this._NaN ? double.NaN : _ema);
base.Add(ret, update);
}
} }
+3 -1
View File
@@ -1,3 +1,4 @@
/*
using Xunit; using Xunit;
using System; using System;
using QuanTAlib; using QuanTAlib;
@@ -402,4 +403,5 @@ public class PandasTA : IDisposable
} }
} }
} }
*/
+36 -35
View File
@@ -16,7 +16,7 @@ public class Skender
{ {
bars = new(Bars: 10000, Volatility: 0.5, Drift: 0.0, Precision: 2); bars = new(Bars: 10000, Volatility: 0.5, Drift: 0.0, Precision: 2);
period = rnd.Next(30) + 5; period = rnd.Next(30) + 5;
digits = 5; //minimizing rounding errors in type conversions digits = 6; //minimizing rounding errors in type conversions
skip = period+2; skip = period+2;
quotes = bars.Select(q => new Quote quotes = bars.Select(q => new Quote
@@ -206,20 +206,21 @@ public class Skender
{ {
HMA_Series QL = new(bars.Close, period, useNaN: false); HMA_Series QL = new(bars.Close, period, useNaN: false);
var SK = quotes.GetHma(period).Select(i => i.Hma.Null2NaN()!); var SK = quotes.GetHma(period).Select(i => i.Hma.Null2NaN()!);
for (int i = QL.Length; i > skip; i--) for (int i = QL.Length; i > skip*2; i--)
{ {
double QL_item = QL[i - 1].v; double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1); double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
} }
} }
[Fact] [Fact]
public void KAMA() public void KAMA()
{ {
// TODO: check precision of KAMA() // TODO: check precision of KAMA()
KAMA_Series QL = new(bars.Close, period, useNaN: false); KAMA_Series QL = new(bars.Close, period, useNaN: false);
var SK = quotes.GetKama(period).Select(i => i.Kama.Null2NaN()!); var SK = quotes.GetKama(period).Select(i => i.Kama.Null2NaN()!);
for (int i = QL.Length; i > 250; i--) for (int i = QL.Length; i > skip+2; i--)
{ {
double QL_item = QL[i - 1].v; double QL_item = QL[i - 1].v;
double SK_item = SK.ElementAt(i - 1); double SK_item = SK.ElementAt(i - 1);
@@ -269,8 +270,8 @@ public class Skender
var SK = quotes.GetSmaAnalysis(period).Select(i => i.Mad.Null2NaN()!); var SK = quotes.GetSmaAnalysis(period).Select(i => i.Mad.Null2NaN()!);
for (int i = QL.Length; i > skip; i--) for (int i = QL.Length; i > skip; i--)
{ {
double QL_item = Math.Round(QL[i - 1].v, digits: digits); double QL_item = QL[i - 1].v;
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
} }
} }
@@ -281,11 +282,11 @@ public class Skender
var SK = quotes.GetMama(fastLimit: 0.5, slowLimit: 0.05); var SK = quotes.GetMama(fastLimit: 0.5, slowLimit: 0.05);
for (int i = QL.Length; i > skip; i--) for (int i = QL.Length; i > skip; i--)
{ {
double QL_item = Math.Round(QL[i - 1].v, digits: digits); double QL_item = QL[i - 1].v;
double SK_item = Math.Round(SK.ElementAt(i - 1).Mama.Null2NaN()!, digits: digits); double SK_item = SK.ElementAt(i - 1).Mama.Null2NaN()!;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
QL_item = Math.Round(QL.Fama[i - 1].v, digits: digits); QL_item = QL.Fama[i - 1].v;
SK_item = Math.Round(SK.ElementAt(i - 1).Fama.Null2NaN()!, digits: digits); SK_item = SK.ElementAt(i - 1).Fama.Null2NaN()!;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
} }
} }
@@ -296,8 +297,8 @@ public class Skender
var SK = quotes.GetSmaAnalysis(period).Select(i => i.Mape.Null2NaN()!); var SK = quotes.GetSmaAnalysis(period).Select(i => i.Mape.Null2NaN()!);
for (int i = QL.Length; i > skip; i--) for (int i = QL.Length; i > skip; i--)
{ {
double QL_item = Math.Round(QL[i - 1].v, digits: digits); double QL_item = QL[i - 1].v;
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
} }
} }
@@ -308,8 +309,8 @@ public class Skender
var SK = quotes.GetSmaAnalysis(period).Select(i => i.Mse.Null2NaN()!); var SK = quotes.GetSmaAnalysis(period).Select(i => i.Mse.Null2NaN()!);
for (int i = QL.Length; i > skip; i--) for (int i = QL.Length; i > skip; i--)
{ {
double QL_item = Math.Round(QL[i - 1].v, digits: digits); double QL_item = QL[i - 1].v;
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
} }
} }
@@ -319,9 +320,9 @@ public class Skender
OBV_Series QL = new(bars, period, false); OBV_Series QL = new(bars, period, false);
var SK = quotes.GetObv(period).Select(i => i.Obv!); var SK = quotes.GetObv(period).Select(i => i.Obv!);
for (int i = QL.Length; i > skip; i--) { for (int i = QL.Length; i > skip; i--) {
double QL_item = Math.Round(QL.Last().v, digits: digits); double QL_item = QL.Last().v;
// adding volume[0] to OBV to pass the test and keep compatibility with TA-LIB // adding volume[0] to OBV to pass the test and keep compatibility with TA-LIB
double SK_item = Math.Round(SK.Last()! + (double)quotes.First().Volume!, digits: digits); double SK_item = SK.Last()! + (double)quotes.First().Volume!;
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
} }
} }
@@ -368,8 +369,8 @@ public class Skender
var SK = quotes.GetRsi(period).Select(i => i.Rsi.Null2NaN()!); var SK = quotes.GetRsi(period).Select(i => i.Rsi.Null2NaN()!);
for (int i = QL.Length; i > skip; i--) for (int i = QL.Length; i > skip; i--)
{ {
double QL_item = Math.Round(QL[i - 1].v, digits: digits); double QL_item = QL[i - 1].v;
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
} }
} }
@@ -380,8 +381,8 @@ public class Skender
var SK = quotes.GetStdDev(period).Select(i => i.StdDev.Null2NaN()!); var SK = quotes.GetStdDev(period).Select(i => i.StdDev.Null2NaN()!);
for (int i = QL.Length; i > skip; i--) for (int i = QL.Length; i > skip; i--)
{ {
double QL_item = Math.Round(QL[i - 1].v, digits: digits); double QL_item = QL[i - 1].v;
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
} }
} }
@@ -392,8 +393,8 @@ public class Skender
var SK = quotes.GetSma(period).Select(i => i.Sma.Null2NaN()!); var SK = quotes.GetSma(period).Select(i => i.Sma.Null2NaN()!);
for (int i = QL.Length; i > skip; i--) for (int i = QL.Length; i > skip; i--)
{ {
double QL_item = Math.Round(QL[i - 1].v, digits: digits); double QL_item = QL[i - 1].v;
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
} }
} }
@@ -404,8 +405,8 @@ public class Skender
var SK = quotes.GetSmma(period).Select(i => i.Smma.Null2NaN()!); var SK = quotes.GetSmma(period).Select(i => i.Smma.Null2NaN()!);
for (int i = QL.Length; i > skip; i--) for (int i = QL.Length; i > skip; i--)
{ {
double QL_item = Math.Round(QL[i - 1].v, digits: digits); double QL_item = QL[i - 1].v;
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
} }
} }
@@ -416,8 +417,8 @@ public class Skender
var SK = quotes.GetT3(lookbackPeriods: period, volumeFactor: 0.7).Select(i => i.T3.Null2NaN()!); var SK = quotes.GetT3(lookbackPeriods: period, volumeFactor: 0.7).Select(i => i.T3.Null2NaN()!);
for (int i = QL.Length; i > period*15; i--) for (int i = QL.Length; i > period*15; i--)
{ {
double QL_item = Math.Round(QL[i - 1].v, digits: digits); double QL_item = QL[i - 1].v;
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
} }
} }
@@ -426,8 +427,8 @@ public class Skender
TRIX_Series QL = new(bars.Close, period, false); TRIX_Series QL = new(bars.Close, period, false);
var SK = quotes.GetTrix(period).Select(i => i.Trix.Null2NaN()!); var SK = quotes.GetTrix(period).Select(i => i.Trix.Null2NaN()!);
for (int i = QL.Length; i > period*12; i--) { for (int i = QL.Length; i > period*12; i--) {
double QL_item = Math.Round(QL[i - 1].v, digits: digits); double QL_item = QL[i - 1].v;
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10, -digits), Math.Pow(10, -digits));
} }
} }
@@ -438,8 +439,8 @@ public class Skender
var SK = quotes.GetTema(period).Select(i => i.Tema.Null2NaN()!); var SK = quotes.GetTema(period).Select(i => i.Tema.Null2NaN()!);
for (int i = QL.Length; i > skip; i--) for (int i = QL.Length; i > skip; i--)
{ {
double QL_item = Math.Round(QL[i - 1].v, digits: digits); double QL_item = QL[i - 1].v;
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
} }
} }
@@ -450,8 +451,8 @@ public class Skender
var SK = quotes.GetTr().Select(i => i.Tr.Null2NaN()!); var SK = quotes.GetTr().Select(i => i.Tr.Null2NaN()!);
for (int i = QL.Length; i > skip; i--) for (int i = QL.Length; i > skip; i--)
{ {
double QL_item = Math.Round(QL[i - 1].v, digits: digits); double QL_item = QL[i - 1].v;
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
} }
} }
@@ -462,8 +463,8 @@ public class Skender
var SK = quotes.GetWma(period).Select(i => i.Wma.Null2NaN()!); var SK = quotes.GetWma(period).Select(i => i.Wma.Null2NaN()!);
for (int i = QL.Length; i > skip*2; i--) for (int i = QL.Length; i > skip*2; i--)
{ {
double QL_item = Math.Round(QL[i - 1].v, digits: digits); double QL_item = QL[i - 1].v;
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
} }
} }
@@ -474,8 +475,8 @@ public class Skender
var SK = quotes.GetStdDev(period).Select(i => i.ZScore.Null2NaN()!); var SK = quotes.GetStdDev(period).Select(i => i.ZScore.Null2NaN()!);
for (int i = QL.Length; i > skip; i--) for (int i = QL.Length; i > skip; i--)
{ {
double QL_item = Math.Round(QL[i - 1].v, digits: digits); double QL_item = QL[i - 1].v;
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits); double SK_item = SK.ElementAt(i - 1);
Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits)); Assert.InRange(SK_item! - QL_item, -Math.Pow(10,-digits), Math.Pow(10,-digits));
} }
} }
+3 -1
View File
@@ -74,7 +74,7 @@ public class Ta_Lib
{ {
ATR_Series QL = new(bars, period, false); ATR_Series QL = new(bars, period, false);
Core.Atr(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period); Core.Atr(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
for (int i = QL.Length - 1; i > skip * 15; i--) for (int i = QL.Length - 1; i > skip; i--)
{ {
double QL_item = Math.Round(QL[i].v, digits: digits); double QL_item = Math.Round(QL[i].v, digits: digits);
double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits); double TA_item = Math.Round(TALIB[i - outBegIdx], digits: digits);
@@ -114,6 +114,7 @@ public class Ta_Lib
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
} }
} }
[Fact] [Fact]
public void CMO() { public void CMO() {
CMO_Series QL = new(bars.Close, period, false); CMO_Series QL = new(bars.Close, period, false);
@@ -124,6 +125,7 @@ public class Ta_Lib
Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); Assert.InRange(TA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
} }
} }
[Fact] [Fact]
public void CORR() public void CORR()
{ {
+6 -2
View File
@@ -20,8 +20,8 @@ public class Tulip_Test
{ {
bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0, Precision: 3); bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0, Precision: 3);
period = rnd.Next(28) + 3; period = rnd.Next(28) + 3;
skip = period+1; skip = period+5;
digits = 10; digits = 8;
outdata = new double[bars.Count]; outdata = new double[bars.Count];
inopen = bars.Open.v.ToArray(); inopen = bars.Open.v.ToArray();
@@ -124,6 +124,7 @@ public class Tulip_Test
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
} }
} }
[Fact] [Fact]
public void CMO() { public void CMO() {
double[][] arrin = { inclose }; double[][] arrin = { inclose };
@@ -214,6 +215,7 @@ public class Tulip_Test
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
} }
} }
[Fact] [Fact]
public void HMA() { public void HMA() {
double[][] arrin = { inclose }; double[][] arrin = { inclose };
@@ -226,6 +228,7 @@ public class Tulip_Test
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
} }
} }
[Fact] [Fact]
public void KAMA() { public void KAMA() {
double[][] arrin = { inclose }; double[][] arrin = { inclose };
@@ -238,6 +241,7 @@ public class Tulip_Test
Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits)); Assert.InRange(TU_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
} }
} }
[Fact] [Fact]
public void LINREG() { public void LINREG() {
double[][] arrin = { inclose }; double[][] arrin = { inclose };