mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-25 13:58:04 +00:00
refactoring
This commit is contained in:
@@ -354,3 +354,4 @@ MigrationBackup/
|
|||||||
# Ionide (cross platform F# VS Code tools) working folder
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
.ionide/
|
.ionide/
|
||||||
dotCover.Output.dcvr
|
dotCover.Output.dcvr
|
||||||
|
/Tests/GlobalSuppressions.cs
|
||||||
|
|||||||
@@ -34,9 +34,11 @@
|
|||||||
<Link>QuanTAlib\%(RecursiveDir)%(Filename)%(Extension)</Link>
|
<Link>QuanTAlib\%(RecursiveDir)%(Filename)%(Extension)</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<!--
|
||||||
<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
|
<Target Name="CopyCustomContent" AfterTargets="AfterBuild">
|
||||||
<Copy SourceFiles=".\bin\$(Configuration)\net48\Quantower_QTAlib.dll" DestinationFolder="\Quantower\Settings\Scripts\Indicators\QuanTAlib" />
|
<Copy SourceFiles=".\bin\$(Configuration)\net48\Quantower_QTAlib.dll" DestinationFolder="\Quantower\Settings\Scripts\Indicators\QuanTAlib" />
|
||||||
</Target>
|
</Target>
|
||||||
|
-->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AdditionalFiles Include="..\.sonarlint\mihakralj_quantalib\CSharp\SonarLint.xml" Link="SonarLint.xml" />
|
<AdditionalFiles Include="..\.sonarlint\mihakralj_quantalib\CSharp\SonarLint.xml" Link="SonarLint.xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
namespace QuanTAlib;
|
namespace QuanTAlib;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
/* <summary>
|
/* <summary>
|
||||||
Abstract classes with all scaffolding required to build indicators.
|
Abstract classes with all scaffolding required to build indicators.
|
||||||
@@ -17,50 +18,54 @@ Abstract classes with all scaffolding required to build indicators.
|
|||||||
</summary> */
|
</summary> */
|
||||||
public abstract class Single_TSeries_Indicator : TSeries
|
public abstract class Single_TSeries_Indicator : TSeries
|
||||||
{
|
{
|
||||||
protected readonly int _period;
|
protected readonly int _period;
|
||||||
protected readonly bool _NaN;
|
protected readonly bool _NaN;
|
||||||
protected readonly TSeries _data;
|
protected readonly TSeries _data;
|
||||||
protected int _p;
|
protected int _p;
|
||||||
|
|
||||||
// Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN)
|
// Chainable Constructor - add it at the end of primary constructor :base(source: source, period: period, useNaN: useNaN)
|
||||||
protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN)
|
protected Single_TSeries_Indicator(TSeries source, int period, bool useNaN)
|
||||||
|
{
|
||||||
|
this._data = source;
|
||||||
|
this._period = period;
|
||||||
|
this._p = _period;
|
||||||
|
this._NaN = useNaN;
|
||||||
|
this._data.Pub += this.Sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
// overridable Add() method to add/update a single item at the end of the list
|
||||||
|
|
||||||
|
public virtual void Add((System.DateTime t, double v) TValue, bool update, bool useNaN)
|
||||||
|
{
|
||||||
|
if (_period == 0) { _p = this.Length; }
|
||||||
|
var res = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : TValue.v);
|
||||||
|
base.Add(res, 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)
|
||||||
|
public virtual void Add(TSeries data) { 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) => this.Add(TValue: TValue, update: false);
|
||||||
|
public void Add(bool update) => this.Add(TValue: this._data[this._data.Count - 1], update: update);
|
||||||
|
public void Add() => this.Add(TValue: this._data[this._data.Count - 1], update: false);
|
||||||
|
public new void Sub(object source, TSeriesEventArgs e) => this.Add(TValue: this._data[this._data.Count - 1], update: e.update);
|
||||||
|
|
||||||
|
protected static void Add_Replace(List<double> l, double v, bool update)
|
||||||
|
{
|
||||||
|
if (update)
|
||||||
|
{ l[l.Count - 1] = v; }
|
||||||
|
else
|
||||||
|
{ l.Add(v); }
|
||||||
|
}
|
||||||
|
protected static double Add_Replace_Trim(List<double> l, double v, int p, bool update)
|
||||||
|
{
|
||||||
|
Add_Replace(l, v, update);
|
||||||
|
double ret = (l.Count > 0) ? l.First() : 0;
|
||||||
|
if (l.Count > p && p != 0)
|
||||||
{
|
{
|
||||||
this._data = source;
|
l.RemoveAt(0);
|
||||||
this._period = period;
|
|
||||||
this._p = _period;
|
|
||||||
this._NaN = useNaN;
|
|
||||||
this._data.Pub += this.Sub;
|
|
||||||
}
|
|
||||||
|
|
||||||
// overridable Add() method to add/update a single item at the end of the list
|
|
||||||
|
|
||||||
public virtual void Add((System.DateTime t, double v) TValue, bool update, bool useNaN)
|
|
||||||
{
|
|
||||||
if (_period == 0) { _p = this.Length; }
|
|
||||||
var res = (TValue.t, this.Count < this._p - 1 && this._NaN ? double.NaN : TValue.v);
|
|
||||||
base.Add(res, 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)
|
|
||||||
public virtual void Add(TSeries data) { 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) => this.Add(TValue: TValue, update: false);
|
|
||||||
public void Add(bool update) => this.Add(TValue: this._data[this._data.Count - 1], update: update);
|
|
||||||
public void Add() => this.Add(TValue: this._data[this._data.Count - 1], update: false);
|
|
||||||
public new void Sub(object source, TSeriesEventArgs e) => this.Add(TValue: this._data[this._data.Count - 1], update: e.update);
|
|
||||||
|
|
||||||
protected static void Add_Replace(List<double> l, double v, bool update)
|
|
||||||
{
|
|
||||||
if (update)
|
|
||||||
{ l[l.Count - 1] = v; }
|
|
||||||
else
|
|
||||||
{ l.Add(v); }
|
|
||||||
}
|
|
||||||
protected static void Add_Replace_Trim(List<double> l, double v, int p, bool update)
|
|
||||||
{
|
|
||||||
Add_Replace(l, v, update);
|
|
||||||
if (l.Count > p && p!=0)
|
|
||||||
{ l.RemoveAt(0); }
|
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,12 +25,14 @@ public class EMA_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;
|
||||||
|
private bool _useSMA;
|
||||||
|
|
||||||
public EMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
|
public EMA_Series(TSeries source, int period, bool useNaN = false, bool useSMA = true) : 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 = 0;
|
||||||
|
_useSMA = useSMA;
|
||||||
if (this._data.Count > 0) { base.Add(this._data); }
|
if (this._data.Count > 0) { base.Add(this._data); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,8 +40,9 @@ public class EMA_Series : Single_TSeries_Indicator
|
|||||||
{
|
{
|
||||||
double _ema;
|
double _ema;
|
||||||
if (update) { this._lastema = this._lastlastema; }
|
if (update) { this._lastema = this._lastlastema; }
|
||||||
|
if (this.Count == 0) { _lastema = TValue.v; }
|
||||||
|
|
||||||
if (this.Count < this._p)
|
if (this.Count < this._p && _useSMA)
|
||||||
{
|
{
|
||||||
Add_Replace(_buffer, TValue.v, update);
|
Add_Replace(_buffer, TValue.v, update);
|
||||||
_ema = 0;
|
_ema = 0;
|
||||||
|
|||||||
+39
-14
@@ -1,6 +1,5 @@
|
|||||||
namespace QuanTAlib;
|
namespace QuanTAlib;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
/* <summary>
|
/* <summary>
|
||||||
SMA: Simple Moving Average
|
SMA: Simple Moving Average
|
||||||
@@ -19,19 +18,45 @@ Remark:
|
|||||||
|
|
||||||
public class SMA_Series : Single_TSeries_Indicator
|
public class SMA_Series : Single_TSeries_Indicator
|
||||||
{
|
{
|
||||||
public SMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
|
private readonly System.Collections.Generic.List<double> _buffer = new();
|
||||||
{
|
private double _sma, _oldsma;
|
||||||
if (base._data.Count > 0) { base.Add(base._data); }
|
private double _topv, _oldtopv;
|
||||||
}
|
public SMA_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN)
|
||||||
private readonly System.Collections.Generic.List<double> _buffer = new();
|
{
|
||||||
|
if (base._data.Count > 0)
|
||||||
|
{ base.Add(base._data); }
|
||||||
|
}
|
||||||
|
public override void Add((System.DateTime t, double v) TValue, bool update)
|
||||||
|
{
|
||||||
|
_topv = Add_Replace_Trim(_buffer, TValue.v, _p, update);
|
||||||
|
|
||||||
public override void Add((System.DateTime t, double v) TValue, bool update)
|
// rolling back if update, storing data for potential future update
|
||||||
{
|
if (update)
|
||||||
Add_Replace_Trim(_buffer, TValue.v, _p, update);
|
{
|
||||||
double _sma = 0;
|
_sma = _oldsma;
|
||||||
for (int i=0; i<_buffer.Count; i++) { _sma+= _buffer[i]; }
|
_topv = _oldtopv;
|
||||||
_sma /= _buffer.Count;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_oldsma = _sma;
|
||||||
|
_oldtopv = _topv;
|
||||||
|
}
|
||||||
|
|
||||||
base.Add((TValue.t, _sma), update, _NaN);
|
// main additive calculation of SMA - for data points that are larger than _p period
|
||||||
}
|
// this.Count > _p
|
||||||
|
if (this.Count > _p)
|
||||||
|
{
|
||||||
|
_sma += (TValue.v - _topv) / _p;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// calculate SMA the traditional way (sum all, divide with _p) for data points within _p period
|
||||||
|
_sma = 0;
|
||||||
|
for (int i = 0; i < _buffer.Count; i++)
|
||||||
|
{ _sma += _buffer[i]; }
|
||||||
|
_sma /= _buffer.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Add((TValue.t, _sma), update, _NaN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -20,10 +20,10 @@ public class ADOSC_Series : Single_TBars_Indicator
|
|||||||
private double _lastema1, _lastlastema1, _lastema2, _lastlastema2;
|
private double _lastema1, _lastlastema1, _lastema2, _lastlastema2;
|
||||||
private double _lastadl, _lastlastadl;
|
private double _lastadl, _lastlastadl;
|
||||||
|
|
||||||
public ADOSC_Series(TBars source, bool useNaN = false) : base(source, period: 0, useNaN)
|
public ADOSC_Series(TBars source, int shortPeriod = 3, int longPeriod =10, bool useNaN = false) : base(source, period: 0, useNaN)
|
||||||
{
|
{
|
||||||
_k1 = 2.0 / (3 + 1);
|
_k1 = 2.0 / (shortPeriod + 1);
|
||||||
_k2 = 2.0 / (10 + 1);
|
_k2 = 2.0 / (longPeriod + 1);
|
||||||
_lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
|
_lastadl = _lastlastadl = _lastema1 = _lastlastema1 = _lastema2 = _lastlastema2 = 0;
|
||||||
if (_bars.Count > 0) { base.Add(_bars); }
|
if (_bars.Count > 0) { base.Add(_bars); }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
<PackageReference Include="TALib.NETCore" Version="0.4.4" />
|
<PackageReference Include="TALib.NETCore" Version="0.4.4" />
|
||||||
<PackageReference Include="Skender.Stock.Indicators" Version="2.4.0" />
|
<PackageReference Include="Skender.Stock.Indicators" Version="2.4.0" />
|
||||||
<PackageReference Include="pythonnet" Version="3.0.1" />
|
<PackageReference Include="pythonnet" Version="3.0.1" />
|
||||||
|
<PackageReference Include="Tulip.NETCore" Version="0.8.0.1" />
|
||||||
|
<PackageReference Include="System.Text.Json" Version="7.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -28,5 +30,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Remove="Python.Included" />
|
<None Remove="Python.Included" />
|
||||||
<None Remove="pythonnet" />
|
<None Remove="pythonnet" />
|
||||||
|
<None Remove="Tulip.NETCore" />
|
||||||
|
<None Remove="System.Text.Json" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
using System;
|
||||||
|
using QuanTAlib;
|
||||||
|
using Skender.Stock.Indicators;
|
||||||
|
using Tulip;
|
||||||
|
using Python.Runtime;
|
||||||
|
using Python.Included;
|
||||||
|
using TALib;
|
||||||
|
using Validations;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace One.by.one;
|
||||||
|
public class Dema : IDisposable
|
||||||
|
{
|
||||||
|
private readonly GBM_Feed bars;
|
||||||
|
private readonly Random rnd = new();
|
||||||
|
private readonly int period, skip;
|
||||||
|
private readonly double precision;
|
||||||
|
|
||||||
|
private readonly IEnumerable<Quote> quotes;
|
||||||
|
private readonly double[] outdata;
|
||||||
|
private readonly double[] inopen;
|
||||||
|
private readonly double[] inhigh;
|
||||||
|
private readonly double[] inlow;
|
||||||
|
private readonly double[] inclose;
|
||||||
|
private readonly double[] involume;
|
||||||
|
|
||||||
|
private readonly string OStype;
|
||||||
|
private readonly dynamic np;
|
||||||
|
private readonly dynamic ta;
|
||||||
|
private readonly dynamic df;
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
PythonEngine.Shutdown();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
public Dema()
|
||||||
|
{
|
||||||
|
bars = new(Bars: 1000, Volatility: 0.5, Drift: 0.0);
|
||||||
|
period = rnd.Next(30) + 5;
|
||||||
|
skip = period*8;
|
||||||
|
precision = 1e-6;
|
||||||
|
|
||||||
|
quotes = bars.Select(q => new Quote
|
||||||
|
{
|
||||||
|
Date = q.t,
|
||||||
|
Open = (decimal)q.o,
|
||||||
|
High = (decimal)q.h,
|
||||||
|
Low = (decimal)q.l,
|
||||||
|
Close = (decimal)q.c,
|
||||||
|
Volume = (decimal)q.v
|
||||||
|
});
|
||||||
|
|
||||||
|
outdata = new double[bars.Count];
|
||||||
|
inopen = bars.Open.v.ToArray();
|
||||||
|
inhigh = bars.High.v.ToArray();
|
||||||
|
inlow = bars.Low.v.ToArray();
|
||||||
|
inclose = bars.Close.v.ToArray();
|
||||||
|
involume = bars.Volume.v.ToArray();
|
||||||
|
|
||||||
|
// Checking the host OS and setting PythonDLL accordingly
|
||||||
|
OStype = Environment.OSVersion.ToString();
|
||||||
|
if (OStype == "Unix 13.1.0")
|
||||||
|
OStype = @"/usr/local/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/libpython3.10.dylib";
|
||||||
|
else
|
||||||
|
OStype = Path.GetFullPath(".") + @"\python-3.10.0-embed-amd64\python310.dll";
|
||||||
|
|
||||||
|
Installer.InstallPath = Path.GetFullPath(path: ".");
|
||||||
|
Installer.SetupPython().Wait();
|
||||||
|
Installer.TryInstallPip();
|
||||||
|
Installer.PipInstallModule(module_name: "pandas-ta");
|
||||||
|
Runtime.PythonDLL = OStype;
|
||||||
|
PythonEngine.Initialize();
|
||||||
|
np = Py.Import(name: "numpy");
|
||||||
|
ta = Py.Import(name: "pandas_ta");
|
||||||
|
|
||||||
|
string[] cols = { "open", "high", "low", "close", "volume" };
|
||||||
|
double[,] ary = new double[bars.Count, 5];
|
||||||
|
for (int i = 0; i < bars.Count; i++) {
|
||||||
|
ary[i, 0] = bars.Open[i].v;
|
||||||
|
ary[i, 1] = bars.High[i].v;
|
||||||
|
ary[i, 2] = bars.Low[i].v;
|
||||||
|
ary[i, 3] = bars.Close[i].v;
|
||||||
|
ary[i, 4] = bars.Volume[i].v;
|
||||||
|
}
|
||||||
|
df = ta.DataFrame(data: np.array(ary), index: np.array(bars.Close.t), columns: np.array(cols));
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void WeirdData() {
|
||||||
|
DEMA_Series QL = new(source: bars.Close, period);
|
||||||
|
var lastData = bars.Close.Last();
|
||||||
|
var lastCalc = QL.Last();
|
||||||
|
QL.Add((DateTime.Today.AddDays(1), double.NaN), update: true);
|
||||||
|
Assert.NotEqual(lastCalc, QL.Last()); //value changed
|
||||||
|
QL.Add(lastData, update: true);
|
||||||
|
Assert.Equal(lastCalc, QL.Last()); // back to the same data
|
||||||
|
|
||||||
|
QL.Add((DateTime.Today.AddDays(-1), double.NegativeInfinity), update: true);
|
||||||
|
Assert.NotEqual(lastCalc, QL.Last()); //value changed
|
||||||
|
QL.Add(lastData, update: true);
|
||||||
|
Assert.Equal(lastCalc, QL.Last()); // back to the same data
|
||||||
|
|
||||||
|
QL.Add((new DateTime(), double.Epsilon), update: true);
|
||||||
|
Assert.NotEqual(lastCalc, QL.Last()); //value changed
|
||||||
|
QL.Add(lastData, update: true);
|
||||||
|
Assert.Equal(lastCalc, QL.Last()); // back to the same data
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Updating() {
|
||||||
|
DEMA_Series QL = new(source: bars.Close, period);
|
||||||
|
var lastData = bars.Close.Last();
|
||||||
|
var lastCalc = QL.Last();
|
||||||
|
int lastLen = QL.Count;
|
||||||
|
QL.Add((DateTime.Today, 0), update: true);
|
||||||
|
Assert.NotEqual(lastCalc, QL.Last()); //value changed
|
||||||
|
QL.Add(lastData, update: true);
|
||||||
|
Assert.Equal(lastLen, QL.Count); // same size
|
||||||
|
Assert.Equal(lastCalc, QL.Last()); // same data
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Skender_Test()
|
||||||
|
{
|
||||||
|
DEMA_Series QL = new(bars.Close, period, false);
|
||||||
|
var SK = quotes.GetDema(period).Select(i => i.Dema.Null2NaN()!);
|
||||||
|
for (int i = QL.Length; i > skip; i--)
|
||||||
|
{
|
||||||
|
double QL_item = QL[i - 1].v;
|
||||||
|
double SK_item = SK.ElementAt(i - 1);
|
||||||
|
Assert.InRange(SK_item! - QL_item, -precision, precision);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void TALIB_Test()
|
||||||
|
{
|
||||||
|
DEMA_Series QL = new(bars.Close, period, false);
|
||||||
|
Core.Dema(inclose, 0, bars.Count - 1, outdata, out int outBegIdx, out _, period);
|
||||||
|
for (int i = QL.Length - 1; i > skip; i--)
|
||||||
|
{
|
||||||
|
double QL_item = QL[i].v;
|
||||||
|
double TA_item = outdata[i - outBegIdx];
|
||||||
|
Assert.InRange(TA_item! - QL_item, -precision, precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Tulip_Test() {
|
||||||
|
double[][] arrin = { inclose };
|
||||||
|
double[][] arrout = { outdata };
|
||||||
|
DEMA_Series QL = new(bars.Close, period: period, useNaN: false);
|
||||||
|
Tulip.Indicators.dema.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
|
||||||
|
for (int i = QL.Length - 1; i > skip*3; i--) {
|
||||||
|
double QL_item = QL[i].v;
|
||||||
|
double TU_item = arrout[0][i];
|
||||||
|
Assert.InRange(TU_item! - QL_item, -precision, precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
void PandasTA_Test() {
|
||||||
|
DEMA_Series QL = new(bars.Close, period, false);
|
||||||
|
var pta = df.ta.dema(close: df.close, length: period);
|
||||||
|
for (int i = QL.Length; i > skip; i--) {
|
||||||
|
double QL_item = QL[i - 1].v;
|
||||||
|
double PanTA_item = (double)pta[i - 1];
|
||||||
|
Assert.InRange(PanTA_item! - QL_item, -1e-5, 1e-5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
using System;
|
||||||
|
using QuanTAlib;
|
||||||
|
using Skender.Stock.Indicators;
|
||||||
|
using Tulip;
|
||||||
|
using Python.Runtime;
|
||||||
|
using Python.Included;
|
||||||
|
using TALib;
|
||||||
|
using Validations;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace One.by.one;
|
||||||
|
public class Ema : IDisposable
|
||||||
|
{
|
||||||
|
private readonly GBM_Feed bars;
|
||||||
|
private readonly Random rnd = new();
|
||||||
|
private readonly int period, skip;
|
||||||
|
private readonly double precision;
|
||||||
|
|
||||||
|
private readonly IEnumerable<Quote> quotes;
|
||||||
|
private readonly double[] outdata;
|
||||||
|
private readonly double[] inopen;
|
||||||
|
private readonly double[] inhigh;
|
||||||
|
private readonly double[] inlow;
|
||||||
|
private readonly double[] inclose;
|
||||||
|
private readonly double[] involume;
|
||||||
|
|
||||||
|
private readonly string OStype;
|
||||||
|
private readonly dynamic np;
|
||||||
|
private readonly dynamic ta;
|
||||||
|
private readonly dynamic df;
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
PythonEngine.Shutdown();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
public Ema()
|
||||||
|
{
|
||||||
|
bars = new(Bars: 1000, Volatility: 0.5, Drift: 0.0);
|
||||||
|
period = rnd.Next(30) + 5;
|
||||||
|
skip = period-1;
|
||||||
|
precision = 1e-8;
|
||||||
|
|
||||||
|
quotes = bars.Select(q => new Quote
|
||||||
|
{
|
||||||
|
Date = q.t,
|
||||||
|
Open = (decimal)q.o,
|
||||||
|
High = (decimal)q.h,
|
||||||
|
Low = (decimal)q.l,
|
||||||
|
Close = (decimal)q.c,
|
||||||
|
Volume = (decimal)q.v
|
||||||
|
});
|
||||||
|
|
||||||
|
outdata = new double[bars.Count];
|
||||||
|
inopen = bars.Open.v.ToArray();
|
||||||
|
inhigh = bars.High.v.ToArray();
|
||||||
|
inlow = bars.Low.v.ToArray();
|
||||||
|
inclose = bars.Close.v.ToArray();
|
||||||
|
involume = bars.Volume.v.ToArray();
|
||||||
|
|
||||||
|
// Checking the host OS and setting PythonDLL accordingly
|
||||||
|
OStype = Environment.OSVersion.ToString();
|
||||||
|
if (OStype == "Unix 13.1.0")
|
||||||
|
OStype = @"/usr/local/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/libpython3.10.dylib";
|
||||||
|
else
|
||||||
|
OStype = Path.GetFullPath(".") + @"\python-3.10.0-embed-amd64\python310.dll";
|
||||||
|
|
||||||
|
Installer.InstallPath = Path.GetFullPath(path: ".");
|
||||||
|
Installer.SetupPython().Wait();
|
||||||
|
Installer.TryInstallPip();
|
||||||
|
Installer.PipInstallModule(module_name: "pandas-ta");
|
||||||
|
Runtime.PythonDLL = OStype;
|
||||||
|
PythonEngine.Initialize();
|
||||||
|
np = Py.Import(name: "numpy");
|
||||||
|
ta = Py.Import(name: "pandas_ta");
|
||||||
|
|
||||||
|
string[] cols = { "open", "high", "low", "close", "volume" };
|
||||||
|
double[,] ary = new double[bars.Count, 5];
|
||||||
|
for (int i = 0; i < bars.Count; i++) {
|
||||||
|
ary[i, 0] = bars.Open[i].v;
|
||||||
|
ary[i, 1] = bars.High[i].v;
|
||||||
|
ary[i, 2] = bars.Low[i].v;
|
||||||
|
ary[i, 3] = bars.Close[i].v;
|
||||||
|
ary[i, 4] = bars.Volume[i].v;
|
||||||
|
}
|
||||||
|
df = ta.DataFrame(data: np.array(ary), index: np.array(bars.Close.t), columns: np.array(cols));
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void WeirdData() {
|
||||||
|
EMA_Series QL = new(source: bars.Close, period);
|
||||||
|
var lastData = bars.Close.Last();
|
||||||
|
var lastCalc = QL.Last();
|
||||||
|
QL.Add((DateTime.Today.AddDays(1), double.NaN), update: true);
|
||||||
|
Assert.NotEqual(lastCalc, QL.Last()); //value changed
|
||||||
|
QL.Add(lastData, update: true);
|
||||||
|
Assert.Equal(lastCalc, QL.Last()); // back to the same data
|
||||||
|
|
||||||
|
QL.Add((DateTime.Today.AddDays(-1), double.NegativeInfinity), update: true);
|
||||||
|
Assert.NotEqual(lastCalc, QL.Last()); //value changed
|
||||||
|
QL.Add(lastData, update: true);
|
||||||
|
Assert.Equal(lastCalc, QL.Last()); // back to the same data
|
||||||
|
|
||||||
|
QL.Add((new DateTime(), double.Epsilon), update: true);
|
||||||
|
Assert.NotEqual(lastCalc, QL.Last()); //value changed
|
||||||
|
QL.Add(lastData, update: true);
|
||||||
|
Assert.Equal(lastCalc, QL.Last()); // back to the same data
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Updating() {
|
||||||
|
EMA_Series QL = new(source: bars.Close, period);
|
||||||
|
var lastData = bars.Close.Last();
|
||||||
|
var lastCalc = QL.Last();
|
||||||
|
int lastLen = QL.Count;
|
||||||
|
QL.Add((DateTime.Today, 0), update: true);
|
||||||
|
Assert.NotEqual(lastCalc, QL.Last()); //value changed
|
||||||
|
QL.Add(lastData, update: true);
|
||||||
|
Assert.Equal(lastLen, QL.Count); // same size
|
||||||
|
Assert.Equal(lastCalc, QL.Last()); // same data
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Skender_Test()
|
||||||
|
{
|
||||||
|
EMA_Series QL = new(bars.Close, period, false);
|
||||||
|
var SK = quotes.GetEma(period).Select(i => i.Ema.Null2NaN()!);
|
||||||
|
for (int i = QL.Length; i > skip; i--)
|
||||||
|
{
|
||||||
|
double QL_item = QL[i - 1].v;
|
||||||
|
double SK_item = SK.ElementAt(i - 1);
|
||||||
|
Assert.InRange(SK_item! - QL_item, -precision, precision);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void TALIB_Test()
|
||||||
|
{
|
||||||
|
EMA_Series QL = new(bars.Close, period, false);
|
||||||
|
Core.Ema(inclose, 0, bars.Count - 1, outdata, out int outBegIdx, out _, period);
|
||||||
|
for (int i = QL.Length - 1; i > skip; i--)
|
||||||
|
{
|
||||||
|
double QL_item = QL[i].v;
|
||||||
|
double TA_item = outdata[i - outBegIdx];
|
||||||
|
Assert.InRange(TA_item! - QL_item, -precision, precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Tulip_Test() {
|
||||||
|
double[][] arrin = { inclose };
|
||||||
|
double[][] arrout = { outdata };
|
||||||
|
EMA_Series QL = new(bars.Close, period: period, useNaN: false, useSMA: false);
|
||||||
|
Tulip.Indicators.ema.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
|
||||||
|
for (int i = QL.Length - 1; i > skip; i--) {
|
||||||
|
double QL_item = QL[i].v;
|
||||||
|
double TU_item = arrout[0][i];
|
||||||
|
Assert.InRange(TU_item! - QL_item, -precision, precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
void PandasTA_Test() {
|
||||||
|
EMA_Series QL = new(bars.Close, period, false);
|
||||||
|
var pta = df.ta.ema(close: df.close, length: period);
|
||||||
|
for (int i = QL.Length; i > skip; i--) {
|
||||||
|
double QL_item = QL[i - 1].v;
|
||||||
|
double PanTA_item = (double)pta[i - 1];
|
||||||
|
Assert.InRange(PanTA_item! - QL_item, -1e-5, 1e-5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
using System;
|
||||||
|
using QuanTAlib;
|
||||||
|
using Skender.Stock.Indicators;
|
||||||
|
using Tulip;
|
||||||
|
using Python.Runtime;
|
||||||
|
using Python.Included;
|
||||||
|
using TALib;
|
||||||
|
using Validations;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace One.by.one;
|
||||||
|
public class SMA : IDisposable {
|
||||||
|
private readonly GBM_Feed bars;
|
||||||
|
private readonly Random rnd = new();
|
||||||
|
private readonly int period, skip;
|
||||||
|
private readonly double precision;
|
||||||
|
|
||||||
|
private readonly IEnumerable<Quote> quotes;
|
||||||
|
private readonly double[] outdata;
|
||||||
|
private readonly double[] inopen;
|
||||||
|
private readonly double[] inhigh;
|
||||||
|
private readonly double[] inlow;
|
||||||
|
private readonly double[] inclose;
|
||||||
|
private readonly double[] involume;
|
||||||
|
|
||||||
|
private readonly string OStype;
|
||||||
|
private readonly dynamic np;
|
||||||
|
private readonly dynamic ta;
|
||||||
|
private readonly dynamic df;
|
||||||
|
|
||||||
|
public void Dispose() {
|
||||||
|
PythonEngine.Shutdown();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
public SMA() {
|
||||||
|
bars = new(Bars: 1000, Volatility: 0.5, Drift: 0.0);
|
||||||
|
period = rnd.Next(30) + 5;
|
||||||
|
precision = 1e-8;
|
||||||
|
skip = period-1;
|
||||||
|
|
||||||
|
quotes = bars.Select(q => new Quote {
|
||||||
|
Date = q.t,
|
||||||
|
Open = (decimal)q.o,
|
||||||
|
High = (decimal)q.h,
|
||||||
|
Low = (decimal)q.l,
|
||||||
|
Close = (decimal)q.c,
|
||||||
|
Volume = (decimal)q.v
|
||||||
|
});
|
||||||
|
|
||||||
|
outdata = new double[bars.Count];
|
||||||
|
inopen = bars.Open.v.ToArray();
|
||||||
|
inhigh = bars.High.v.ToArray();
|
||||||
|
inlow = bars.Low.v.ToArray();
|
||||||
|
inclose = bars.Close.v.ToArray();
|
||||||
|
involume = bars.Volume.v.ToArray();
|
||||||
|
|
||||||
|
// Checking the host OS and setting PythonDLL accordingly
|
||||||
|
OStype = Environment.OSVersion.ToString();
|
||||||
|
if (OStype == "Unix 13.1.0")
|
||||||
|
OStype = @"/usr/local/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/libpython3.10.dylib";
|
||||||
|
else
|
||||||
|
OStype = Path.GetFullPath(".") + @"\python-3.10.0-embed-amd64\python310.dll";
|
||||||
|
|
||||||
|
Installer.InstallPath = Path.GetFullPath(path: ".");
|
||||||
|
Installer.SetupPython().Wait();
|
||||||
|
Installer.TryInstallPip();
|
||||||
|
Installer.PipInstallModule(module_name: "pandas-ta");
|
||||||
|
Runtime.PythonDLL = OStype;
|
||||||
|
PythonEngine.Initialize();
|
||||||
|
np = Py.Import(name: "numpy");
|
||||||
|
ta = Py.Import(name: "pandas_ta");
|
||||||
|
|
||||||
|
string[] cols = { "open", "high", "low", "close", "volume" };
|
||||||
|
double[,] ary = new double[bars.Count, 5];
|
||||||
|
for (int i = 0; i < bars.Count; i++) {
|
||||||
|
ary[i, 0] = bars.Open[i].v;
|
||||||
|
ary[i, 1] = bars.High[i].v;
|
||||||
|
ary[i, 2] = bars.Low[i].v;
|
||||||
|
ary[i, 3] = bars.Close[i].v;
|
||||||
|
ary[i, 4] = bars.Volume[i].v;
|
||||||
|
}
|
||||||
|
df = ta.DataFrame(data: np.array(ary), index: np.array(bars.Close.t), columns: np.array(cols));
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void WeirdData() {
|
||||||
|
SMA_Series QL = new(source: bars.Close, period);
|
||||||
|
var lastData = bars.Close.Last();
|
||||||
|
var lastCalc = QL.Last();
|
||||||
|
QL.Add((DateTime.Today.AddDays(1), double.NaN), update: true);
|
||||||
|
Assert.NotEqual(lastCalc, QL.Last()); //value changed
|
||||||
|
QL.Add(lastData, update: true);
|
||||||
|
Assert.Equal(lastCalc, QL.Last()); // back to the same data
|
||||||
|
|
||||||
|
QL.Add((DateTime.Today.AddDays(-1), double.NegativeInfinity), update: true);
|
||||||
|
Assert.NotEqual(lastCalc, QL.Last()); //value changed
|
||||||
|
QL.Add(lastData, update: true);
|
||||||
|
Assert.Equal(lastCalc, QL.Last()); // back to the same data
|
||||||
|
|
||||||
|
QL.Add((new DateTime(), double.Epsilon), update: true);
|
||||||
|
Assert.NotEqual(lastCalc, QL.Last()); //value changed
|
||||||
|
QL.Add(lastData, update: true);
|
||||||
|
Assert.Equal(lastCalc, QL.Last()); // back to the same data
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Updating() {
|
||||||
|
SMA_Series QL = new(source: bars.Close, period);
|
||||||
|
var lastData = bars.Close.Last();
|
||||||
|
var lastCalc = QL.Last();
|
||||||
|
int lastLen = QL.Count;
|
||||||
|
QL.Add((DateTime.Today, 0), update: true);
|
||||||
|
Assert.NotEqual(lastCalc, QL.Last()); //value changed
|
||||||
|
QL.Add(lastData, update: true);
|
||||||
|
Assert.Equal(lastLen, QL.Count); // same size
|
||||||
|
Assert.Equal(lastCalc, QL.Last()); // same data
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Skender_Test() {
|
||||||
|
SMA_Series QL = new(bars.Close, period, false);
|
||||||
|
var SK = quotes.GetSma(period).Select(i => i.Sma.Null2NaN()!);
|
||||||
|
for (int i = QL.Length; i > skip; i--) {
|
||||||
|
double QL_item = QL[i - 1].v;
|
||||||
|
double SK_item = SK.ElementAt(i - 1);
|
||||||
|
Assert.InRange(SK_item! - QL_item, -precision, precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void TALIB_Test() {
|
||||||
|
SMA_Series QL = new(bars.Close, period, false);
|
||||||
|
Core.Sma(inclose, 0, bars.Count - 1, outdata, out int outBegIdx, out _, period);
|
||||||
|
for (int i = QL.Length - 1; i > skip; i--) {
|
||||||
|
double QL_item = QL[i].v;
|
||||||
|
double TA_item = outdata[i - outBegIdx];
|
||||||
|
Assert.InRange(TA_item! - QL_item, -precision, precision);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void Tulip_Test() {
|
||||||
|
double[][] arrin = { inclose };
|
||||||
|
double[][] arrout = { outdata };
|
||||||
|
SMA_Series QL = new(bars.Close, period, false);
|
||||||
|
Tulip.Indicators.sma.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
|
||||||
|
for (int i = QL.Length - 1; i > skip; i--) {
|
||||||
|
double QL_item = QL[i].v;
|
||||||
|
double TU_item = arrout[0][i - period + 1];
|
||||||
|
Assert.InRange(TU_item! - QL_item, -precision, precision);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
void PandasTA_Test() {
|
||||||
|
SMA_Series QL = new(bars.Close, period, false);
|
||||||
|
var pta = df.ta.sma(close: df.close, length: period);
|
||||||
|
for (int i = QL.Length; i > skip; i--) {
|
||||||
|
double QL_item = QL[i - 1].v;
|
||||||
|
double PanTA_item = (double)pta[i - 1];
|
||||||
|
Assert.InRange(PanTA_item! - QL_item, -precision, precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ public class PandasTA : IDisposable
|
|||||||
{
|
{
|
||||||
private readonly GBM_Feed bars;
|
private readonly GBM_Feed bars;
|
||||||
private readonly Random rnd = new();
|
private readonly Random rnd = new();
|
||||||
private readonly int period;
|
private readonly int period, sample;
|
||||||
private int digits;
|
private int digits;
|
||||||
private readonly string OStype;
|
private readonly string OStype;
|
||||||
private readonly dynamic np;
|
private readonly dynamic np;
|
||||||
@@ -19,10 +19,14 @@ public class PandasTA : IDisposable
|
|||||||
public PandasTA() {
|
public PandasTA() {
|
||||||
bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0);
|
bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0);
|
||||||
period = rnd.Next(maxValue: 28) + 3;
|
period = rnd.Next(maxValue: 28) + 3;
|
||||||
digits = 4; //minimizing rounding errors in type conversions
|
sample = 200;
|
||||||
|
digits = 3; //minimizing rounding errors in type conversions
|
||||||
|
|
||||||
// Checking the host OS and setting PythonDLL accordingly
|
// Checking the host OS and setting PythonDLL accordingly
|
||||||
OStype = Path.GetFullPath(path: ".") + @"\python-3.10.0-embed-amd64\python310.dll";
|
OStype = Environment.OSVersion.ToString();
|
||||||
|
if (OStype == "Unix 13.1.0")
|
||||||
|
OStype = @"/usr/local/Cellar/python@3.10/3.10.8/Frameworks/Python.framework/Versions/3.10/lib/libpython3.10.dylib";
|
||||||
|
else OStype = Path.GetFullPath(".") + @"\python-3.10.0-embed-amd64\python310.dll";
|
||||||
|
|
||||||
Installer.InstallPath = Path.GetFullPath(path: ".");
|
Installer.InstallPath = Path.GetFullPath(path: ".");
|
||||||
Installer.SetupPython().Wait();
|
Installer.SetupPython().Wait();
|
||||||
@@ -53,7 +57,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void ADL() {
|
[Fact] void ADL() {
|
||||||
ADL_Series QL = new(bars);
|
ADL_Series QL = new(bars);
|
||||||
var pta = df.ta.ad(high: df.high, low: df.low, close:df.close, volume:df.volume);
|
var pta = df.ta.ad(high: df.high, low: df.low, close:df.close, volume:df.volume);
|
||||||
for (int i = QL.Length; i > 0; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i-1].v, digits: digits);
|
double QL_item = Math.Round(QL[i-1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i-1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i-1], digits: digits);
|
||||||
@@ -63,7 +67,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void ADOSC() {
|
[Fact] void ADOSC() {
|
||||||
ADOSC_Series QL = new(bars);
|
ADOSC_Series QL = new(bars);
|
||||||
var pta = df.ta.adosc(high: df.high, low: df.low, close: df.close, volume: df.volume);
|
var pta = df.ta.adosc(high: df.high, low: df.low, close: df.close, volume: df.volume);
|
||||||
for (int i = QL.Length; i > 0; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -73,7 +77,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void ATR() {
|
[Fact] void ATR() {
|
||||||
ATR_Series QL = new(bars, period);
|
ATR_Series QL = new(bars, period);
|
||||||
var pta = df.ta.atr(high: df.high, low: df.low, close: df.close, length: period);
|
var pta = df.ta.atr(high: df.high, low: df.low, close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > 0; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -83,7 +87,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void BIAS() {
|
[Fact] void BIAS() {
|
||||||
BIAS_Series QL = new(bars.Close, period, false);
|
BIAS_Series QL = new(bars.Close, period, false);
|
||||||
var pta = df.ta.bias(close: df.close, length: period);
|
var pta = df.ta.bias(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > period-1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -93,7 +97,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void DEMA() {
|
[Fact] void DEMA() {
|
||||||
DEMA_Series QL = new(bars.Close, period, false);
|
DEMA_Series QL = new(bars.Close, period, false);
|
||||||
var pta = df.ta.dema(close: df.close, length: period);
|
var pta = df.ta.dema(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > period-1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -103,7 +107,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void EMA() {
|
[Fact] void EMA() {
|
||||||
EMA_Series QL = new(bars.Close, period, false);
|
EMA_Series QL = new(bars.Close, period, false);
|
||||||
var pta = df.ta.ema(close: df.close, length: period);
|
var pta = df.ta.ema(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > period-1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -113,7 +117,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void ENTROPY() {
|
[Fact] void ENTROPY() {
|
||||||
ENTROPY_Series QL = new(bars.Close, period, useNaN: false);
|
ENTROPY_Series QL = new(bars.Close, period, useNaN: false);
|
||||||
var pta = df.ta.entropy(close: df.close, length: period);
|
var pta = df.ta.entropy(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > period+1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -122,7 +126,7 @@ public class PandasTA : IDisposable
|
|||||||
}
|
}
|
||||||
[Fact] void HL2() {
|
[Fact] void HL2() {
|
||||||
var pta = df.ta.hl2(high: df.high, low: df.low);
|
var pta = df.ta.hl2(high: df.high, low: df.low);
|
||||||
for (int i = bars.HL2.Length; i > 0; i--)
|
for (int i = bars.HL2.Length; i > bars.HL2.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(bars.HL2[i - 1].v, digits: digits);
|
double QL_item = Math.Round(bars.HL2[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -131,7 +135,7 @@ public class PandasTA : IDisposable
|
|||||||
}
|
}
|
||||||
[Fact] void HLC3() {
|
[Fact] void HLC3() {
|
||||||
var pta = df.ta.hlc3(high: df.high, low: df.low, close: df.close);
|
var pta = df.ta.hlc3(high: df.high, low: df.low, close: df.close);
|
||||||
for (int i = bars.HLC3.Length; i > 0; i--)
|
for (int i = bars.HLC3.Length; i > bars.HLC3.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(bars.HLC3[i - 1].v, digits: digits);
|
double QL_item = Math.Round(bars.HLC3[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -141,7 +145,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void HMA() {
|
[Fact] void HMA() {
|
||||||
HMA_Series QL = new(bars.Close, period, false);
|
HMA_Series QL = new(bars.Close, period, false);
|
||||||
var pta = df.ta.hma(close: df.close, length: period);
|
var pta = df.ta.hma(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > period+1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -152,7 +156,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void KAMA() {
|
[Fact] void KAMA() {
|
||||||
KAMA_Series QL = new(bars.Close, period);
|
KAMA_Series QL = new(bars.Close, period);
|
||||||
var pta = df.ta.kama(close: df.close, length: period);
|
var pta = df.ta.kama(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > 0; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -162,7 +166,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void KURTOSIS() {
|
[Fact] void KURTOSIS() {
|
||||||
KURTOSIS_Series QL = new(bars.Close, period, useNaN: false);
|
KURTOSIS_Series QL = new(bars.Close, period, useNaN: false);
|
||||||
var pta = df.ta.kurtosis(close: df.close, length: period);
|
var pta = df.ta.kurtosis(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > period+1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -173,7 +177,7 @@ public class PandasTA : IDisposable
|
|||||||
{
|
{
|
||||||
MAD_Series QL = new(bars.Close, period, useNaN: false);
|
MAD_Series QL = new(bars.Close, period, useNaN: false);
|
||||||
var pta = df.ta.mad(close: df.close, length: period);
|
var pta = df.ta.mad(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > period-1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -183,7 +187,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void MEDIAN() {
|
[Fact] void MEDIAN() {
|
||||||
MEDIAN_Series QL = new(bars.Close, period);
|
MEDIAN_Series QL = new(bars.Close, period);
|
||||||
var pta = df.ta.median(close: df.close, length: period);
|
var pta = df.ta.median(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > period-1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -193,7 +197,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void OBV() {
|
[Fact] void OBV() {
|
||||||
OBV_Series QL = new(bars);
|
OBV_Series QL = new(bars);
|
||||||
var pta = df.ta.obv(close: df.close, volume: df.volume);
|
var pta = df.ta.obv(close: df.close, volume: df.volume);
|
||||||
for (int i = QL.Length; i > 0; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -202,7 +206,7 @@ public class PandasTA : IDisposable
|
|||||||
}
|
}
|
||||||
[Fact] void OHLC4() {
|
[Fact] void OHLC4() {
|
||||||
var pta = df.ta.ohlc4(open: df.open, high: df.high, low: df.low, close: df.close);
|
var pta = df.ta.ohlc4(open: df.open, high: df.high, low: df.low, close: df.close);
|
||||||
for (int i = bars.OHLC4.Length; i > 0; i--)
|
for (int i = bars.OHLC4.Length; i > bars.OHLC4.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(bars.OHLC4[i - 1].v, digits: digits);
|
double QL_item = Math.Round(bars.OHLC4[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -212,7 +216,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void RMA() {
|
[Fact] void RMA() {
|
||||||
RMA_Series QL = new(bars.Close, period, false);
|
RMA_Series QL = new(bars.Close, period, false);
|
||||||
var pta = df.ta.rma(close: df.close, length: period);
|
var pta = df.ta.rma(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > 0; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -222,7 +226,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void RSI() {
|
[Fact] void RSI() {
|
||||||
RSI_Series QL = new(bars.Close, period);
|
RSI_Series QL = new(bars.Close, period);
|
||||||
var pta = df.ta.rsi(close: df.close, length: period);
|
var pta = df.ta.rsi(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > 0; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -232,7 +236,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void SDEV() {
|
[Fact] void SDEV() {
|
||||||
SDEV_Series QL = new(bars.Close, period, useNaN: false);
|
SDEV_Series QL = new(bars.Close, period, useNaN: false);
|
||||||
var pta = df.ta.stdev(close: df.close, length: period, ddof: 0);
|
var pta = df.ta.stdev(close: df.close, length: period, ddof: 0);
|
||||||
for (int i = QL.Length; i > period-1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -242,7 +246,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void SMA() {
|
[Fact] void SMA() {
|
||||||
SMA_Series QL = new(bars.Close, period, false);
|
SMA_Series QL = new(bars.Close, period, false);
|
||||||
var pta = df.ta.sma(close: df.close, length: period);
|
var pta = df.ta.sma(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > period-1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -252,27 +256,29 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void SSDEV() {
|
[Fact] void SSDEV() {
|
||||||
SSDEV_Series QL = new(bars.Close, period, useNaN: false);
|
SSDEV_Series QL = new(bars.Close, period, useNaN: false);
|
||||||
var pta = df.ta.stdev(close: df.close, length: period, ddof: 1);
|
var pta = df.ta.stdev(close: df.close, length: period, ddof: 1);
|
||||||
for (int i = QL.Length; i > period-1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
Assert.Equal(PanTA_item, QL_item);
|
Assert.Equal(PanTA_item, QL_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
[Fact] void SVARIANCE() {
|
[Fact] void SVARIANCE() {
|
||||||
SVAR_Series QL = new(bars.Close, period);
|
SVAR_Series QL = new(bars.Close, period);
|
||||||
var pta = df.ta.variance(close: df.close, length: period, ddof: 1);
|
var pta = df.ta.variance(close: df.close, length: period, ddof: 1);
|
||||||
for (int i = QL.Length; i > 0; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
Assert.Equal(PanTA_item, QL_item);
|
Assert.Equal(PanTA_item, QL_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
[Fact] void T3() {
|
[Fact] void T3() {
|
||||||
T3_Series QL = new(source: bars.Close, period: period, vfactor: 0.7, useNaN: false);
|
T3_Series QL = new(source: bars.Close, period: period, vfactor: 0.7, useNaN: false);
|
||||||
var pta = df.ta.t3(close: df.close, length: period, a: 0.7);
|
var pta = df.ta.t3(close: df.close, length: period, a: 0.7);
|
||||||
for (int i = QL.Length; i > 0; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -282,7 +288,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void TEMA() {
|
[Fact] void TEMA() {
|
||||||
TEMA_Series QL = new(bars.Close, period, false);
|
TEMA_Series QL = new(bars.Close, period, false);
|
||||||
var pta = df.ta.tema(close: df.close, length: period);
|
var pta = df.ta.tema(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -292,7 +298,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void TR() {
|
[Fact] void TR() {
|
||||||
TR_Series QL = new(bars);
|
TR_Series QL = new(bars);
|
||||||
var pta = df.ta.true_range(high: df.high, low: df.low, close: df.close);
|
var pta = df.ta.true_range(high: df.high, low: df.low, close: df.close);
|
||||||
for (int i = QL.Length; i > 1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -303,7 +309,7 @@ public class PandasTA : IDisposable
|
|||||||
// TODO: return length to variable length (period) when Pandas-TA fixes trima to calculate even periods right
|
// TODO: return length to variable length (period) when Pandas-TA fixes trima to calculate even periods right
|
||||||
TRIMA_Series QL = new(bars.Close, 11);
|
TRIMA_Series QL = new(bars.Close, 11);
|
||||||
var pta = df.ta.trima(close: df.close, length: 11);
|
var pta = df.ta.trima(close: df.close, length: 11);
|
||||||
for (int i = QL.Length; i > period-1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -313,7 +319,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void VARIANCE() {
|
[Fact] void VARIANCE() {
|
||||||
VAR_Series QL = new(bars.Close, period);
|
VAR_Series QL = new(bars.Close, period);
|
||||||
var pta = df.ta.variance(close: df.close, length: period, ddof:0);
|
var pta = df.ta.variance(close: df.close, length: period, ddof:0);
|
||||||
for (int i = QL.Length; i > 0; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -323,7 +329,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void WMA() {
|
[Fact] void WMA() {
|
||||||
WMA_Series QL = new(bars.Close, period, false);
|
WMA_Series QL = new(bars.Close, period, false);
|
||||||
var pta = df.ta.wma(close: df.close, length: period);
|
var pta = df.ta.wma(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > period-1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -333,7 +339,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void ZLEMA() {
|
[Fact] void ZLEMA() {
|
||||||
ZLEMA_Series QL = new(bars.Close, period, false);
|
ZLEMA_Series QL = new(bars.Close, period, false);
|
||||||
var pta = df.ta.zlma(close: df.close, length: period);
|
var pta = df.ta.zlma(close: df.close, length: period);
|
||||||
for (int i = QL.Length; i > 0; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -343,7 +349,7 @@ public class PandasTA : IDisposable
|
|||||||
[Fact] void ZSCORE() {
|
[Fact] void ZSCORE() {
|
||||||
ZSCORE_Series QL = new(bars.Close, period, useNaN: false);
|
ZSCORE_Series QL = new(bars.Close, period, useNaN: false);
|
||||||
var pta = df.ta.zscore(close: df.close, length: period, ddof: 0);
|
var pta = df.ta.zscore(close: df.close, length: period, ddof: 0);
|
||||||
for (int i = QL.Length; i > period-1; i--)
|
for (int i = QL.Length; i > QL.Length-sample; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
double PanTA_item = Math.Round((double)pta[i - 1], digits: digits);
|
||||||
@@ -4,18 +4,20 @@ using Skender.Stock.Indicators;
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Validations;
|
namespace Validations;
|
||||||
public class Skender_Stock
|
public class Skender
|
||||||
{
|
{
|
||||||
private readonly GBM_Feed bars;
|
private readonly GBM_Feed bars;
|
||||||
private readonly Random rnd = new();
|
private readonly Random rnd = new();
|
||||||
private readonly int period, digits;
|
private readonly int period, digits, skip;
|
||||||
private readonly IEnumerable<Quote> quotes;
|
private readonly IEnumerable<Quote> quotes;
|
||||||
|
|
||||||
public Skender_Stock()
|
|
||||||
|
public 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 = 4; //minimizing rounding errors in type conversions
|
digits = 2; //minimizing rounding errors in type conversions
|
||||||
|
skip = 300;
|
||||||
|
|
||||||
quotes = bars.Select(q => new Quote
|
quotes = bars.Select(q => new Quote
|
||||||
{
|
{
|
||||||
@@ -27,27 +29,26 @@ public class Skender_Stock
|
|||||||
Volume = (decimal)q.v
|
Volume = (decimal)q.v
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ADL()
|
public void ADL()
|
||||||
{
|
{
|
||||||
// TODO: check precision of ADL()
|
// TODO: check precision of ADL()
|
||||||
ADL_Series QL = new(bars, false);
|
ADL_Series QL = new(bars, false);
|
||||||
var SK = quotes.GetAdl().Select(i => i.Adl);
|
var SK = quotes.GetAdl().Select(i => i.Adl);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1)!, digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1)!, digits: digits);
|
||||||
Assert.Equal(SK_item!, QL_item);
|
Assert.Equal(SK_item!, QL_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ALMA()
|
public void ALMA()
|
||||||
{
|
{
|
||||||
ALMA_Series QL = new(bars.Close, period, useNaN: false);
|
ALMA_Series QL = new(bars.Close, period, useNaN: false);
|
||||||
var SK = quotes.GetAlma(period).Select(i => i.Alma.Null2NaN()!);
|
var SK = quotes.GetAlma(period).Select(i => i.Alma.Null2NaN()!);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
||||||
@@ -59,7 +60,7 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
ATR_Series QL = new(bars, period, false);
|
ATR_Series QL = new(bars, period, false);
|
||||||
var SK = quotes.GetAtr(period).Select(i => i.Atr.Null2NaN()!);
|
var SK = quotes.GetAtr(period).Select(i => i.Atr.Null2NaN()!);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
||||||
@@ -71,7 +72,7 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
ATRP_Series QL = new(bars, period, false);
|
ATRP_Series QL = new(bars, period, false);
|
||||||
var SK = quotes.GetAtr(period).Select(i => i.Atrp.Null2NaN()!);
|
var SK = quotes.GetAtr(period).Select(i => i.Atrp.Null2NaN()!);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
||||||
@@ -83,7 +84,7 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
BBANDS_Series QL = new(bars.Close, period, 2.0, useNaN: false);
|
BBANDS_Series QL = new(bars.Close, period, 2.0, useNaN: false);
|
||||||
var SK = quotes.GetBollingerBands(period, 2.0);
|
var SK = quotes.GetBollingerBands(period, 2.0);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL.Mid[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL.Mid[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1).Sma!.Value, digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1).Sma!.Value, digits: digits);
|
||||||
@@ -110,7 +111,7 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
CCI_Series QL = new(bars, period, false);
|
CCI_Series QL = new(bars, period, false);
|
||||||
var SK = quotes.GetCci(period).Select(i => i.Cci.Null2NaN()!);
|
var SK = quotes.GetCci(period).Select(i => i.Cci.Null2NaN()!);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
||||||
@@ -122,20 +123,19 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
CORR_Series QL = new(bars.High, bars.Low, period, false);
|
CORR_Series QL = new(bars.High, bars.Low, period, false);
|
||||||
var SK = quotes.Use(CandlePart.High).GetCorrelation(quotes.Use(CandlePart.Low), period).Select(i => i.Correlation.Null2NaN()!);
|
var SK = quotes.Use(CandlePart.High).GetCorrelation(quotes.Use(CandlePart.Low), period).Select(i => i.Correlation.Null2NaN()!);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
||||||
Assert.Equal(SK_item!, QL_item);
|
Assert.Equal(SK_item!, QL_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void COVAR()
|
public void COVAR()
|
||||||
{
|
{
|
||||||
COVAR_Series QL = new(bars.High, bars.Low, period, false);
|
COVAR_Series QL = new(bars.High, bars.Low, period, false);
|
||||||
var SK = quotes.Use(CandlePart.High).GetCorrelation(quotes.Use(CandlePart.Low), period).Select(i => i.Covariance.Null2NaN()!);
|
var SK = quotes.Use(CandlePart.High).GetCorrelation(quotes.Use(CandlePart.Low), period).Select(i => i.Covariance.Null2NaN()!);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
||||||
@@ -147,33 +147,32 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
DEMA_Series QL = new(bars.Close, period, false);
|
DEMA_Series QL = new(bars.Close, period, false);
|
||||||
var SK = quotes.GetDema(period).Select(i => i.Dema.Null2NaN()!);
|
var SK = quotes.GetDema(period).Select(i => i.Dema.Null2NaN()!);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
||||||
Assert.Equal(SK_item!, QL_item);
|
Assert.Equal(SK_item!, QL_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void EMA()
|
public void EMA()
|
||||||
{
|
{
|
||||||
EMA_Series QL = new(bars.Close, period, false);
|
EMA_Series QL = new(bars.Close, period, false);
|
||||||
var SK = quotes.GetEma(period).Select(i => i.Ema.Null2NaN()!);
|
var SK = quotes.GetEma(period).Select(i => i.Ema.Null2NaN()!);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1), digits: digits);
|
||||||
Assert.Equal(SK_item!, QL_item);
|
Assert.Equal(SK_item!, QL_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
[Fact]
|
[Fact]
|
||||||
public void HL2()
|
public void HL2()
|
||||||
{
|
{
|
||||||
TSeries QL = bars.HL2;
|
TSeries QL = bars.HL2;
|
||||||
var SK = quotes.GetBaseQuote(CandlePart.HL2).Select(i => i.Value);
|
var SK = quotes.GetBaseQuote(CandlePart.HL2).Select(i => i.Value);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1)!, digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1)!, digits: digits);
|
||||||
@@ -185,33 +184,33 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
TSeries QL = bars.HLC3;
|
TSeries QL = bars.HLC3;
|
||||||
var SK = quotes.GetBaseQuote(CandlePart.HLC3).Select(i => i.Value);
|
var SK = quotes.GetBaseQuote(CandlePart.HLC3).Select(i => i.Value);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1)!, digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1)!, digits: digits);
|
||||||
Assert.Equal(SK_item!, QL_item);
|
Assert.Equal(SK_item!, QL_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
[Fact]
|
[Fact]
|
||||||
public void HMA()
|
public void HMA()
|
||||||
{
|
{
|
||||||
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 > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
||||||
Assert.Equal(SK_item!, QL_item);
|
Assert.Equal(SK_item!, QL_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
[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 > 600; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
||||||
@@ -223,7 +222,7 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
LINREG_Series QL = new(bars.Close, period, useNaN: false);
|
LINREG_Series QL = new(bars.Close, period, useNaN: false);
|
||||||
var SK = quotes.GetSlope(period);
|
var SK = quotes.GetSlope(period);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1).Slope!, digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1).Slope!, digits: digits);
|
||||||
@@ -244,7 +243,7 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
MACD_Series QL = new(bars.Close, 26, 12, 9, useNaN: false);
|
MACD_Series QL = new(bars.Close, 26, 12, 9, useNaN: false);
|
||||||
var SK = quotes.GetMacd(12, 26, 9);
|
var SK = quotes.GetMacd(12, 26, 9);
|
||||||
for (int i = QL.Length; i > 500; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1).Macd.Null2NaN()!, digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1).Macd.Null2NaN()!, digits: digits);
|
||||||
@@ -259,7 +258,7 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
MAD_Series QL = new(bars.Close, period, false);
|
MAD_Series QL = new(bars.Close, period, false);
|
||||||
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 > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
||||||
@@ -271,7 +270,7 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
MAMA_Series QL = new(bars.HL2, fastlimit: 0.5, slowlimit: 0.05);
|
MAMA_Series QL = new(bars.HL2, fastlimit: 0.5, slowlimit: 0.05);
|
||||||
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 > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1).Mama.Null2NaN()!, digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1).Mama.Null2NaN()!, digits: digits);
|
||||||
@@ -286,7 +285,7 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
MAPE_Series QL = new(bars.Close, period, false);
|
MAPE_Series QL = new(bars.Close, period, false);
|
||||||
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 > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
||||||
@@ -298,7 +297,7 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
MSE_Series QL = new(bars.Close, period, false);
|
MSE_Series QL = new(bars.Close, period, false);
|
||||||
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 > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
||||||
@@ -311,27 +310,32 @@ public class Skender_Stock
|
|||||||
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!);
|
||||||
// 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
|
||||||
Assert.Equal(Math.Round(SK.Last()! + (double)quotes.First().Volume!, digits: digits), Math.Round(QL.Last().v, digits: digits));
|
for (int i = QL.Length; i > skip; i--)
|
||||||
|
{
|
||||||
|
double QL_item = Math.Round(QL.Last().v, digits: digits);
|
||||||
|
double SK_item = Math.Round(SK.Last()! + (double)quotes.First().Volume!, digits: digits);
|
||||||
|
Assert.Equal(SK_item!, QL_item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
[Fact]
|
[Fact]
|
||||||
public void OC2()
|
public void OC2()
|
||||||
{
|
{
|
||||||
TSeries QL = bars.OC2;
|
TSeries QL = bars.OC2;
|
||||||
var SK = quotes.GetBaseQuote(CandlePart.OC2).Select(i => i.Value);
|
var SK = quotes.GetBaseQuote(CandlePart.OC2).Select(i => i.Value);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1)!, digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1)!, digits: digits);
|
||||||
Assert.Equal(SK_item!, QL_item);
|
Assert.Equal(SK_item!, QL_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[Fact]
|
[Fact]
|
||||||
public void OHL3()
|
public void OHL3()
|
||||||
{
|
{
|
||||||
TSeries QL = bars.OHL3;
|
TSeries QL = bars.OHL3;
|
||||||
var SK = quotes.GetBaseQuote(CandlePart.OHL3).Select(i => i.Value);
|
var SK = quotes.GetBaseQuote(CandlePart.OHL3).Select(i => i.Value);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1)!, digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1)!, digits: digits);
|
||||||
@@ -343,20 +347,20 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
TSeries QL = bars.OHLC4;
|
TSeries QL = bars.OHLC4;
|
||||||
var SK = quotes.GetBaseQuote(CandlePart.OHLC4).Select(i => i.Value);
|
var SK = quotes.GetBaseQuote(CandlePart.OHLC4).Select(i => i.Value);
|
||||||
for (int i = QL.Length; i > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round((double)SK.ElementAt(i - 1)!, digits: digits);
|
double SK_item = Math.Round((double)SK.ElementAt(i - 1)!, digits: digits);
|
||||||
Assert.Equal(SK_item!, QL_item);
|
Assert.Equal(SK_item!, QL_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
[Fact]
|
[Fact]
|
||||||
public void RSI()
|
public void RSI()
|
||||||
{
|
{
|
||||||
RSI_Series QL = new(bars.Close, period, useNaN: false);
|
RSI_Series QL = new(bars.Close, period, useNaN: false);
|
||||||
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 > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
||||||
@@ -368,7 +372,7 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
SDEV_Series QL = new(bars.Close, period, useNaN: false);
|
SDEV_Series QL = new(bars.Close, period, useNaN: false);
|
||||||
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 > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
||||||
@@ -380,7 +384,7 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
SMA_Series QL = new(bars.Close, period, false);
|
SMA_Series QL = new(bars.Close, period, false);
|
||||||
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 > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
||||||
@@ -392,33 +396,31 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
SMMA_Series QL = new(bars.Close, period, useNaN: false);
|
SMMA_Series QL = new(bars.Close, period, useNaN: false);
|
||||||
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 > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
||||||
Assert.Equal(SK_item!, QL_item);
|
Assert.Equal(SK_item!, QL_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void T3()
|
public void T3()
|
||||||
{
|
{
|
||||||
T3_Series QL = new(source: bars.Close, period: period, vfactor: 0.7, false);
|
T3_Series QL = new(source: bars.Close, period: period, vfactor: 0.7, false);
|
||||||
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; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
||||||
Assert.Equal(SK_item!, QL_item);
|
Assert.Equal(SK_item!, QL_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TEMA()
|
public void TEMA()
|
||||||
{
|
{
|
||||||
TEMA_Series QL = new(bars.Close, period, false);
|
TEMA_Series QL = new(bars.Close, period, false);
|
||||||
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 > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
||||||
@@ -430,33 +432,31 @@ public class Skender_Stock
|
|||||||
{
|
{
|
||||||
TR_Series QL = new(bars, useNaN: false);
|
TR_Series QL = new(bars, useNaN: false);
|
||||||
var SK = quotes.GetTr().Select(i => i.Tr.Null2NaN()!);
|
var SK = quotes.GetTr().Select(i => i.Tr.Null2NaN()!);
|
||||||
for (int i = QL.Length; i > 1; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
||||||
Assert.Equal(SK_item!, QL_item);
|
Assert.Equal(SK_item!, QL_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void WMA()
|
public void WMA()
|
||||||
{
|
{
|
||||||
WMA_Series QL = new(bars.Close, period, false);
|
WMA_Series QL = new(bars.Close, period, false);
|
||||||
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 > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
||||||
Assert.Equal(SK_item!, QL_item);
|
Assert.Equal(SK_item!, QL_item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ZSCORE()
|
public void ZSCORE()
|
||||||
{
|
{
|
||||||
ZSCORE_Series QL = new(bars.Close, period, useNaN: false);
|
ZSCORE_Series QL = new(bars.Close, period, useNaN: false);
|
||||||
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 > period; i--)
|
for (int i = QL.Length; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
double QL_item = Math.Round(QL[i - 1].v, digits: digits);
|
||||||
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
double SK_item = Math.Round(SK.ElementAt(i - 1), digits: digits);
|
||||||
@@ -8,7 +8,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
private readonly GBM_Feed bars;
|
private readonly GBM_Feed bars;
|
||||||
private readonly Random rnd = new();
|
private readonly Random rnd = new();
|
||||||
private readonly int period, digits;
|
private readonly int period, digits, skip;
|
||||||
private readonly double[] TALIB;
|
private readonly double[] TALIB;
|
||||||
private readonly double[] TALIB2;
|
private readonly double[] TALIB2;
|
||||||
private readonly double[] inopen;
|
private readonly double[] inopen;
|
||||||
@@ -21,6 +21,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
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 = 200;
|
||||||
digits = 6;
|
digits = 6;
|
||||||
|
|
||||||
TALIB = new double[bars.Count];
|
TALIB = new double[bars.Count];
|
||||||
@@ -37,7 +38,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
ADD_Series QL = new(bars.Open, bars.Close);
|
ADD_Series QL = new(bars.Open, bars.Close);
|
||||||
Core.Add(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
Core.Add(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -59,9 +60,9 @@ public class Ta_Lib
|
|||||||
[Fact]
|
[Fact]
|
||||||
public void ADOSC()
|
public void ADOSC()
|
||||||
{
|
{
|
||||||
ADOSC_Series QL = new(bars, false);
|
ADOSC_Series QL = new(bars, 3, 10, false);
|
||||||
Core.AdOsc(inhigh, inlow, inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
Core.AdOsc(inhigh, inlow, inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -73,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 > outBegIdx * 15; i--)
|
for (int i = QL.Length - 1; i > skip * 15; 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);
|
||||||
@@ -88,7 +89,7 @@ public class Ta_Lib
|
|||||||
double[] outLower = new double[bars.Count];
|
double[] outLower = new double[bars.Count];
|
||||||
BBANDS_Series QL = new(bars.Close, period: 26, multiplier: 2.0, false);
|
BBANDS_Series QL = new(bars.Close, period: 26, multiplier: 2.0, false);
|
||||||
Core.Bbands(inclose, 0, bars.Count - 1, outRealUpperBand: outUpper, outRealMiddleBand: outMiddle, outRealLowerBand: outLower, out int outBegIdx, out _, optInTimePeriod: 26, optInNbDevUp: 2.0, optInNbDevDn: 2.0);
|
Core.Bbands(inclose, 0, bars.Count - 1, outRealUpperBand: outUpper, outRealMiddleBand: outMiddle, outRealLowerBand: outLower, out int outBegIdx, out _, optInTimePeriod: 26, optInNbDevUp: 2.0, optInNbDevDn: 2.0);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; i--)
|
for (int i = QL.Length - 1; i > skip; i--)
|
||||||
{
|
{
|
||||||
double QL_item = Math.Round(QL.Upper[i].v, digits: digits);
|
double QL_item = Math.Round(QL.Upper[i].v, digits: digits);
|
||||||
double TA_item = Math.Round(outUpper[i - outBegIdx], digits: digits);
|
double TA_item = Math.Round(outUpper[i - outBegIdx], digits: digits);
|
||||||
@@ -109,7 +110,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
CCI_Series QL = new(bars, period, false);
|
CCI_Series QL = new(bars, period, false);
|
||||||
Core.Cci(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.Cci(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -121,7 +122,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
CORR_Series QL = new(bars.Open, bars.Close, period);
|
CORR_Series QL = new(bars.Open, bars.Close, period);
|
||||||
Core.Correl(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, optInTimePeriod: period);
|
Core.Correl(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, optInTimePeriod: period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -133,7 +134,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
DEMA_Series QL = new(bars.Close, period, false);
|
DEMA_Series QL = new(bars.Close, period, false);
|
||||||
Core.Dema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.Dema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -145,7 +146,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
DIV_Series QL = new(bars.Open, bars.Close);
|
DIV_Series QL = new(bars.Open, bars.Close);
|
||||||
Core.Div(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
Core.Div(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -157,7 +158,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
EMA_Series QL = new(bars.Close, period, false);
|
EMA_Series QL = new(bars.Close, period, false);
|
||||||
Core.Ema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.Ema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -169,7 +170,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
TSeries QL = bars.HL2;
|
TSeries QL = bars.HL2;
|
||||||
Core.MedPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
Core.MedPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -181,7 +182,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
TSeries QL = bars.HLC3;
|
TSeries QL = bars.HLC3;
|
||||||
Core.TypPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
Core.TypPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -193,7 +194,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
TSeries QL = bars.HLCC4;
|
TSeries QL = bars.HLCC4;
|
||||||
Core.WclPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
Core.WclPrice(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -207,7 +208,7 @@ public class Ta_Lib
|
|||||||
double[] macdHist = new double[bars.Count];
|
double[] macdHist = new double[bars.Count];
|
||||||
MACD_Series QL = new(bars.Close, slow: 26, fast: 12, signal: 9, false);
|
MACD_Series QL = new(bars.Close, slow: 26, fast: 12, signal: 9, false);
|
||||||
Core.Macd(inclose, 0, bars.Count - 1, outMacd: TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _);
|
Core.Macd(inclose, 0, bars.Count - 1, outMacd: TALIB, outMacdSignal: macdSignal, outMacdHist: macdHist, out int outBegIdx, out _);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx * 10; i--)
|
for (int i = QL.Length - 1; i > skip * 10; 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);
|
||||||
@@ -222,7 +223,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
MAMA_Series QL = new(bars.Close, fastlimit: 0.5, slowlimit: 0.05);
|
MAMA_Series QL = new(bars.Close, fastlimit: 0.5, slowlimit: 0.05);
|
||||||
Core.Mama(inReal: inclose, startIdx: 0, endIdx: bars.Count - 1, outMama: TALIB, outFama: TALIB2, outBegIdx: out int outBegIdx, outNbElement: out _, optInFastLimit: 0.5, optInSlowLimit: 0.05);
|
Core.Mama(inReal: inclose, startIdx: 0, endIdx: bars.Count - 1, outMama: TALIB, outFama: TALIB2, outBegIdx: out int outBegIdx, outNbElement: out _, optInFastLimit: 0.5, optInSlowLimit: 0.05);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx * 15; i--)
|
for (int i = QL.Length - 1; i > skip * 15; 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);
|
||||||
@@ -234,7 +235,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
MAX_Series QL = new(bars.Close, period, false);
|
MAX_Series QL = new(bars.Close, period, false);
|
||||||
Core.Max(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.Max(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -246,7 +247,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
MIDPOINT_Series QL = new(bars.Close, period, false);
|
MIDPOINT_Series QL = new(bars.Close, period, false);
|
||||||
Core.MidPoint(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.MidPoint(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -258,7 +259,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
MIDPRICE_Series QL = new(bars, period, false);
|
MIDPRICE_Series QL = new(bars, period, false);
|
||||||
Core.MidPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.MidPrice(inhigh, inlow, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -270,7 +271,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
MIN_Series QL = new(bars.Close, period, false);
|
MIN_Series QL = new(bars.Close, period, false);
|
||||||
Core.Min(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.Min(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -282,7 +283,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
MUL_Series QL = new(bars.Open, bars.Close);
|
MUL_Series QL = new(bars.Open, bars.Close);
|
||||||
Core.Mult(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
Core.Mult(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -294,7 +295,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
OBV_Series QL = new(bars, period, false);
|
OBV_Series QL = new(bars, period, false);
|
||||||
Core.Obv(inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
Core.Obv(inclose, involume, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -306,7 +307,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
TSeries QL = bars.OHLC4;
|
TSeries QL = bars.OHLC4;
|
||||||
Core.AvgPrice(inopen, inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
Core.AvgPrice(inopen, inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -318,7 +319,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
RSI_Series QL = new(bars.Close, period, false);
|
RSI_Series QL = new(bars.Close, period, false);
|
||||||
Core.Rsi(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.Rsi(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -330,7 +331,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
SDEV_Series QL = new(bars.Close, period, false);
|
SDEV_Series QL = new(bars.Close, period, false);
|
||||||
Core.StdDev(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.StdDev(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -342,7 +343,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
SMA_Series QL = new(bars.Close, period, false);
|
SMA_Series QL = new(bars.Close, period, false);
|
||||||
Core.Sma(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.Sma(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -354,7 +355,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
SUB_Series QL = new(bars.Open, bars.Close);
|
SUB_Series QL = new(bars.Open, bars.Close);
|
||||||
Core.Sub(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
Core.Sub(inopen, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -366,7 +367,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
SUM_Series QL = new(bars.Close, period, false);
|
SUM_Series QL = new(bars.Close, period, false);
|
||||||
Core.Sum(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.Sum(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -378,7 +379,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
T3_Series QL = new(source: bars.Close, period: period, vfactor: 0.7, useNaN: false);
|
T3_Series QL = new(source: bars.Close, period: period, vfactor: 0.7, useNaN: false);
|
||||||
Core.T3(inReal: inclose, startIdx: 0, endIdx: bars.Count - 1, outReal: TALIB, outBegIdx: out int outBegIdx, outNbElement: out _, optInTimePeriod: period, optInVFactor: 0.7);
|
Core.T3(inReal: inclose, startIdx: 0, endIdx: bars.Count - 1, outReal: TALIB, outBegIdx: out int outBegIdx, outNbElement: out _, optInTimePeriod: period, optInVFactor: 0.7);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx * 15; i--)
|
for (int i = QL.Length - 1; i > skip * 15; 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);
|
||||||
@@ -390,7 +391,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
TEMA_Series QL = new(bars.Close, period, false);
|
TEMA_Series QL = new(bars.Close, period, false);
|
||||||
Core.Tema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.Tema(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx * 15; i--)
|
for (int i = QL.Length - 1; i > skip * 15; 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);
|
||||||
@@ -402,7 +403,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
TR_Series QL = new(bars, false);
|
TR_Series QL = new(bars, false);
|
||||||
Core.TRange(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
Core.TRange(inhigh, inlow, inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -414,7 +415,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
TRIMA_Series QL = new(bars.Close, period, false);
|
TRIMA_Series QL = new(bars.Close, period, false);
|
||||||
Core.Trima(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.Trima(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -426,7 +427,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
VAR_Series QL = new(bars.Close, period, false);
|
VAR_Series QL = new(bars.Close, period, false);
|
||||||
Core.Var(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.Var(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx * 15; i--)
|
for (int i = QL.Length - 1; i > skip * 15; 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);
|
||||||
@@ -438,7 +439,7 @@ public class Ta_Lib
|
|||||||
{
|
{
|
||||||
WMA_Series QL = new(bars.Close, period, false);
|
WMA_Series QL = new(bars.Close, period, false);
|
||||||
Core.Wma(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
Core.Wma(inclose, 0, bars.Count - 1, TALIB, out int outBegIdx, out _, period);
|
||||||
for (int i = QL.Length - 1; i > outBegIdx; 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);
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
using Xunit;
|
||||||
|
using System;
|
||||||
|
using Tulip;
|
||||||
|
using QuanTAlib;
|
||||||
|
|
||||||
|
namespace Validations;
|
||||||
|
public class Tulip_Test
|
||||||
|
{
|
||||||
|
private readonly GBM_Feed bars;
|
||||||
|
private readonly Random rnd = new();
|
||||||
|
private readonly int period, digits, skip;
|
||||||
|
private readonly double[] outdata;
|
||||||
|
private readonly double[] inopen;
|
||||||
|
private readonly double[] inhigh;
|
||||||
|
private readonly double[] inlow;
|
||||||
|
private readonly double[] inclose;
|
||||||
|
private readonly double[] involume;
|
||||||
|
|
||||||
|
public Tulip_Test()
|
||||||
|
{
|
||||||
|
bars = new(Bars: 5000, Volatility: 0.8, Drift: 0.0, Precision: 3);
|
||||||
|
period = rnd.Next(28) + 3;
|
||||||
|
skip = 600;
|
||||||
|
digits = 5;
|
||||||
|
|
||||||
|
outdata = new double[bars.Count];
|
||||||
|
inopen = bars.Open.v.ToArray();
|
||||||
|
inhigh = bars.High.v.ToArray();
|
||||||
|
inlow = bars.Low.v.ToArray();
|
||||||
|
inclose = bars.Close.v.ToArray()!;
|
||||||
|
involume = bars.Volume.v.ToArray()!;
|
||||||
|
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void AD()
|
||||||
|
{
|
||||||
|
double[][] arrin = {inhigh, inlow, inclose, involume };
|
||||||
|
double[][] arrout = { outdata };
|
||||||
|
ADL_Series QL = new(bars, false);
|
||||||
|
Tulip.Indicators.ad.Run(inputs: arrin, options: new double[] { }, outputs: arrout);
|
||||||
|
for (int i = QL.Length - 1; i > skip; i--)
|
||||||
|
{
|
||||||
|
double QL_item = Math.Round(QL[i].v, digits: digits);
|
||||||
|
double TU_item = Math.Round(arrout[0][i], digits);
|
||||||
|
Assert.Equal(TU_item!, QL_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ADD()
|
||||||
|
{
|
||||||
|
double[][] arrin = { inhigh, inlow };
|
||||||
|
double[][] arrout = { outdata };
|
||||||
|
ADD_Series QL = new(bars.High, bars.Low);
|
||||||
|
Tulip.Indicators.add.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
|
||||||
|
for (int i = QL.Length - 1; i > skip; i--)
|
||||||
|
{
|
||||||
|
double QL_item = Math.Round(QL[i].v, digits: digits);
|
||||||
|
double TU_item = Math.Round(arrout[0][i], digits);
|
||||||
|
Assert.Equal(TU_item!, QL_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ADOSC()
|
||||||
|
{
|
||||||
|
double[][] arrin = { inhigh, inlow, inclose, involume };
|
||||||
|
double[][] arrout = { outdata };
|
||||||
|
int s = 3;
|
||||||
|
ADOSC_Series QL = new(bars, s, period, false);
|
||||||
|
Tulip.Indicators.adosc.Run(inputs: arrin, options: new double[] { s, period }, outputs: arrout);
|
||||||
|
for (int i = QL.Length - 1; i > skip; i--)
|
||||||
|
{
|
||||||
|
double QL_item = Math.Round(QL[i].v, digits: digits);
|
||||||
|
double TU_item = Math.Round(arrout[0][i-period+1], digits);
|
||||||
|
Assert.Equal(TU_item!, QL_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void ATR()
|
||||||
|
{
|
||||||
|
double[][] arrin = { inhigh, inlow, inclose };
|
||||||
|
double[][] arrout = { outdata };
|
||||||
|
|
||||||
|
ATR_Series QL = new(bars, period, false);
|
||||||
|
Tulip.Indicators.atr.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
|
||||||
|
for (int i = QL.Length - 1; i > skip; i--)
|
||||||
|
{
|
||||||
|
double QL_item = Math.Round(QL[i].v, digits: digits);
|
||||||
|
double TU_item = Math.Round(arrout[0][i - period + 1], digits);
|
||||||
|
Assert.Equal(TU_item!, QL_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void BBANDS()
|
||||||
|
{
|
||||||
|
double[][] arrin = { inclose };
|
||||||
|
double[] outmid = new double[bars.Count];
|
||||||
|
double[] outlower = new double[bars.Count];
|
||||||
|
double[] outupper = new double[bars.Count];
|
||||||
|
double[][] arrout = { outlower, outmid, outupper};
|
||||||
|
BBANDS_Series QL = new(bars.Close, period, 2, false);
|
||||||
|
Tulip.Indicators.bbands.Run(inputs: arrin, options: new double[] { period, 2 }, outputs: arrout);
|
||||||
|
for (int i = QL.Length - 1; i > skip; i--)
|
||||||
|
{
|
||||||
|
double QL_item = Math.Round(QL.Lower[i].v, digits: digits);
|
||||||
|
double TU_item = Math.Round(outlower[i - period + 1], digits);
|
||||||
|
Assert.Equal(TU_item!, QL_item);
|
||||||
|
QL_item = Math.Round(QL.Mid[i].v, digits: digits);
|
||||||
|
TU_item = Math.Round(outmid[i - period + 1], digits);
|
||||||
|
Assert.Equal(TU_item!, QL_item);
|
||||||
|
QL_item = Math.Round(QL.Upper[i].v, digits: digits);
|
||||||
|
TU_item = Math.Round(outupper[i - period + 1], digits);
|
||||||
|
Assert.Equal(TU_item!, QL_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void EMA()
|
||||||
|
{
|
||||||
|
double[][] arrin = { inclose };
|
||||||
|
double[][] arrout = { outdata };
|
||||||
|
EMA_Series QL = new(bars.Close, period, false);
|
||||||
|
Tulip.Indicators.ema.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
|
||||||
|
for (int i = QL.Length - 1; i > skip; i--)
|
||||||
|
{
|
||||||
|
double QL_item = Math.Round(QL[i].v, digits: digits);
|
||||||
|
double TU_item = Math.Round(arrout[0][i], digits);
|
||||||
|
Assert.Equal(TU_item!, QL_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void AVGPRICE()
|
||||||
|
{
|
||||||
|
double[][] arrin = { inopen, inhigh, inlow, inclose };
|
||||||
|
double[][] arrout = { outdata };
|
||||||
|
|
||||||
|
TSeries QL = bars.OHLC4;
|
||||||
|
Tulip.Indicators.avgprice.Run(inputs: arrin, options: new double[] { }, outputs: arrout);
|
||||||
|
for (int i = QL.Length - 1; i > skip; i--)
|
||||||
|
{
|
||||||
|
double QL_item = Math.Round(QL[i].v, digits: digits);
|
||||||
|
double TU_item = Math.Round(arrout[0][i], digits);
|
||||||
|
Assert.Equal(TU_item!, QL_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void SMA()
|
||||||
|
{
|
||||||
|
double[][] arrin = { inclose };
|
||||||
|
double[][] arrout = { outdata };
|
||||||
|
SMA_Series QL = new(bars.Close, period, false);
|
||||||
|
Tulip.Indicators.sma.Run(inputs: arrin, options: new double[] { period }, outputs: arrout);
|
||||||
|
for (int i = QL.Length - 1; i > skip; i--)
|
||||||
|
{
|
||||||
|
double QL_item = Math.Round(QL[i].v, digits: digits);
|
||||||
|
double TU_item = Math.Round(arrout[0][i-period+1], digits);
|
||||||
|
Assert.Equal(TU_item!, QL_item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
# SMA: Simple Moving Average
|
||||||
|
SMA is one of the most basic trend-following indicators used in Technical Analysis. It is calculated as the *unweighted mean* of the previous $p$ (period) data-points.
|
||||||
|
|
||||||
|
|
||||||
|
## Calculation
|
||||||
|
|
||||||
|
SMA is a rolling calculation looking backwards from the position ${n}$ and is denoted as ${SMA}_{p}{(data)}$ where $p$ represents the period and $data$ represents the list of data points:
|
||||||
|
$$
|
||||||
|
SMA_p{(data)} = \frac{1}{p}\sum_{i=n-p+1}^{n} data_i
|
||||||
|
$$
|
||||||
|
When calculating the value of next $SMA_{p,next}$ while knowing all previous SMA values, SMA calculation can be reduced to:
|
||||||
|
$$
|
||||||
|
SMA_{p,next} = SMA_{p,prev}+\frac{1}{p}\left( data_{n+1}-data_{n+1-p}\right)
|
||||||
|
$$
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
``` csharp
|
||||||
|
SMA_Series mean = new(source: data, period: p, useNaN: false);
|
||||||
|
|
||||||
|
QuanTA fluent = data.SMA(period: p);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
- `TSeries source` - List of value tuples (DateTime, double)
|
||||||
|
- `int period` - Integer representing the period of SMA
|
||||||
|
- `bool useNaN` - if true, initial values from 1 to period-1 will be replaced with NaN. If false, the initial calculation will return values for SMA(length) instead of SMA(period)
|
||||||
|
|
||||||
|
## Sample chart
|
||||||
|
|
||||||
|
picture of SMA
|
||||||
|
|
||||||
|
## Comparison & Validation
|
||||||
|
|
||||||
|
Validation tests
|
||||||
|
Performance tests
|
||||||
|
|
||||||
|
## References
|
||||||
|
- https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/simple-moving-average-sma/
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
Before Width: | Height: | Size: 89 KiB |
+93
-101
@@ -2,7 +2,14 @@
|
|||||||
"cells": [
|
"cells": [
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {
|
||||||
|
"dotnet_interactive": {
|
||||||
|
"language": "csharp"
|
||||||
|
},
|
||||||
|
"polyglot_notebook": {
|
||||||
|
"kernelName": "csharp"
|
||||||
|
}
|
||||||
|
},
|
||||||
"source": [
|
"source": [
|
||||||
"# Quick Start\n",
|
"# Quick Start\n",
|
||||||
"\n",
|
"\n",
|
||||||
@@ -17,35 +24,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 1,
|
"execution_count": null,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"dotnet_interactive": {
|
"dotnet_interactive": {
|
||||||
"language": "csharp"
|
"language": "csharp"
|
||||||
},
|
},
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"languageId": "dotnet-interactive.csharp"
|
"languageId": "polyglot-notebook"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": [
|
"outputs": [],
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<div><div></div><div></div><div></div></div>"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ename": "Error",
|
|
||||||
"evalue": "(3,1): error CS0246: The type or namespace name 'Yahoo_Feed' could not be found (are you missing a using directive or an assembly reference?)\r\n(10,15): error CS0019: Operator '<' cannot be applied to operands of type 'int' and 'method group'",
|
|
||||||
"output_type": "error",
|
|
||||||
"traceback": [
|
|
||||||
"(3,1): error CS0246: The type or namespace name 'Yahoo_Feed' could not be found (are you missing a using directive or an assembly reference?)\r\n",
|
|
||||||
"(10,15): error CS0019: Operator '<' cannot be applied to operands of type 'int' and 'method group'"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
"source": [
|
||||||
"#r \"nuget:QuanTAlib;\"\n",
|
"#r \"nuget:QuanTAlib;\"\n",
|
||||||
"using QuanTAlib;\n",
|
"using QuanTAlib;\n",
|
||||||
@@ -63,7 +51,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {
|
||||||
|
"dotnet_interactive": {
|
||||||
|
"language": "csharp"
|
||||||
|
},
|
||||||
|
"polyglot_notebook": {
|
||||||
|
"kernelName": "csharp"
|
||||||
|
}
|
||||||
|
},
|
||||||
"source": [
|
"source": [
|
||||||
"## Understanding QuanTAlib data model\n",
|
"## Understanding QuanTAlib data model\n",
|
||||||
"\n",
|
"\n",
|
||||||
@@ -72,26 +67,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 10,
|
"execution_count": null,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"dotnet_interactive": {
|
"dotnet_interactive": {
|
||||||
"language": "csharp"
|
"language": "csharp"
|
||||||
},
|
},
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"languageId": "dotnet-interactive.csharp"
|
"languageId": "polyglot-notebook"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": [
|
"outputs": [],
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<table><thead><tr><th><i>index</i></th><th>Item1</th><th>Item2</th></tr></thead><tbody><tr><td>0</td><td><span>2022-11-10 00:00:00Z</span></td><td><div class=\"dni-plaintext\">105.3</div></td></tr><tr><td>1</td><td><span>2022-11-10 15:47:46Z</span></td><td><div class=\"dni-plaintext\">293.1</div></td></tr><tr><td>2</td><td><span>2022-11-10 15:47:46Z</span></td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>3</td><td><span>2022-11-07 15:47:46Z</span></td><td><div class=\"dni-plaintext\">10</div></td></tr></tbody></table>"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
"source": [
|
||||||
"var item1 = (DateTime.Today, 105.3); // (DateTime, Value) tuple\n",
|
"var item1 = (DateTime.Today, 105.3); // (DateTime, Value) tuple\n",
|
||||||
"double item2 = 293.1; // a simple double\n",
|
"double item2 = 293.1; // a simple double\n",
|
||||||
@@ -107,66 +92,60 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {
|
||||||
|
"dotnet_interactive": {
|
||||||
|
"language": "csharp"
|
||||||
|
},
|
||||||
|
"polyglot_notebook": {
|
||||||
|
"kernelName": "csharp"
|
||||||
|
}
|
||||||
|
},
|
||||||
"source": [
|
"source": [
|
||||||
"TSeries list can display only values (without timestamps) or only timestamps (without values) by using `.v` or `.t` properties"
|
"TSeries list can display only values (without timestamps) or only timestamps (without values) by using `.v` or `.t` properties"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 11,
|
"execution_count": null,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"dotnet_interactive": {
|
"dotnet_interactive": {
|
||||||
"language": "csharp"
|
"language": "csharp"
|
||||||
},
|
},
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"languageId": "dotnet-interactive.csharp"
|
"languageId": "polyglot-notebook"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": [
|
"outputs": [],
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<table><thead><tr><th><i>index</i></th><th>value</th></tr></thead><tbody><tr><td>0</td><td><div class=\"dni-plaintext\">105.3</div></td></tr><tr><td>1</td><td><div class=\"dni-plaintext\">293.1</div></td></tr><tr><td>2</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>3</td><td><div class=\"dni-plaintext\">10</div></td></tr></tbody></table>"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
"source": [
|
||||||
"data.v"
|
"data.v"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {
|
||||||
|
"dotnet_interactive": {
|
||||||
|
"language": "csharp"
|
||||||
|
},
|
||||||
|
"polyglot_notebook": {
|
||||||
|
"kernelName": "csharp"
|
||||||
|
}
|
||||||
|
},
|
||||||
"source": [
|
"source": [
|
||||||
"The last element on the list can be accessed by .Last() or by [^1] - and using `.t` (time) and `.v` (value) properties. Also, casting a TSeries into (double) will return the value of the last element"
|
"The last element on the list can be accessed by .Last() or by [^1] - and using `.t` (time) and `.v` (value) properties. Also, casting a TSeries into (double) will return the value of the last element"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 12,
|
"execution_count": null,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"dotnet_interactive": {
|
"dotnet_interactive": {
|
||||||
"language": "csharp"
|
"language": "csharp"
|
||||||
},
|
},
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"languageId": "dotnet-interactive.csharp"
|
"languageId": "polyglot-notebook"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": [
|
"outputs": [],
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<div class=\"dni-plaintext\">10</div>"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
"source": [
|
||||||
"bool IsTheSame = data.Last().v == data[^1].v;\n",
|
"bool IsTheSame = data.Last().v == data[^1].v;\n",
|
||||||
"double lastvalue = data;\n",
|
"double lastvalue = data;\n",
|
||||||
@@ -176,33 +155,30 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {
|
||||||
|
"dotnet_interactive": {
|
||||||
|
"language": "csharp"
|
||||||
|
},
|
||||||
|
"polyglot_notebook": {
|
||||||
|
"kernelName": "csharp"
|
||||||
|
}
|
||||||
|
},
|
||||||
"source": [
|
"source": [
|
||||||
"All indicators are just modified TSeries classes; they get all required input during class construction (source of the datafeed, period...) and they automatically subscribe to events of the datafeed. Whenever datafeed gets a new value, indicator will calculate its own value. Indicators are also event publishers, so other indicators can subscribe to their results, chaining indicators together:"
|
"All indicators are just modified TSeries classes; they get all required input during class construction (source of the datafeed, period...) and they automatically subscribe to events of the datafeed. Whenever datafeed gets a new value, indicator will calculate its own value. Indicators are also event publishers, so other indicators can subscribe to their results, chaining indicators together:"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 13,
|
"execution_count": null,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"dotnet_interactive": {
|
"dotnet_interactive": {
|
||||||
"language": "csharp"
|
"language": "csharp"
|
||||||
},
|
},
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"languageId": "dotnet-interactive.csharp"
|
"languageId": "polyglot-notebook"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": [
|
"outputs": [],
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<table><thead><tr><th><i>index</i></th><th>value</th></tr></thead><tbody><tr><td>0</td><td><div class=\"dni-plaintext\">Infinity</div></td></tr><tr><td>1</td><td><div class=\"dni-plaintext\">0.6666666666666666</div></td></tr><tr><td>2</td><td><div class=\"dni-plaintext\">0.3333333333333333</div></td></tr><tr><td>3</td><td><div class=\"dni-plaintext\">0.2</div></td></tr><tr><td>4</td><td><div class=\"dni-plaintext\">0.14285714285714285</div></td></tr><tr><td>5</td><td><div class=\"dni-plaintext\">0.1111111111111111</div></td></tr><tr><td>6</td><td><div class=\"dni-plaintext\">0.09090909090909091</div></td></tr><tr><td>7</td><td><div class=\"dni-plaintext\">0.07692307692307693</div></td></tr><tr><td>8</td><td><div class=\"dni-plaintext\">0.06666666666666667</div></td></tr><tr><td>9</td><td><div class=\"dni-plaintext\">0.058823529411764705</div></td></tr><tr><td>10</td><td><div class=\"dni-plaintext\">0.25</div></td></tr></tbody></table>"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
"source": [
|
||||||
"TSeries t1 = new() {0,1,2,3,4,5,6,7,8,9}; // t1 is loaded with data and activated as a publisher\n",
|
"TSeries t1 = new() {0,1,2,3,4,5,6,7,8,9}; // t1 is loaded with data and activated as a publisher\n",
|
||||||
"EMA_Series t2 = new(t1, 3); // t2 will auto-load all history of t1 and wait for events from t1\n",
|
"EMA_Series t2 = new(t1, 3); // t2 will auto-load all history of t1 and wait for events from t1\n",
|
||||||
@@ -218,7 +194,14 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {
|
||||||
|
"dotnet_interactive": {
|
||||||
|
"language": "csharp"
|
||||||
|
},
|
||||||
|
"polyglot_notebook": {
|
||||||
|
"kernelName": "csharp"
|
||||||
|
}
|
||||||
|
},
|
||||||
"source": [
|
"source": [
|
||||||
"# MACD compounded indicator\n",
|
"# MACD compounded indicator\n",
|
||||||
"\n",
|
"\n",
|
||||||
@@ -227,26 +210,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 15,
|
"execution_count": null,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"dotnet_interactive": {
|
"dotnet_interactive": {
|
||||||
"language": "csharp"
|
"language": "csharp"
|
||||||
},
|
},
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"languageId": "dotnet-interactive.csharp"
|
"languageId": "polyglot-notebook"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": [
|
"outputs": [],
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<table><thead><tr><th><i>index</i></th><th>value</th></tr></thead><tbody><tr><td>0</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>1</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>2</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>3</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>4</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>5</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>6</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>7</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>8</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>9</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>10</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>11</td><td><div class=\"dni-plaintext\">0</div></td></tr><tr><td>12</td><td><div class=\"dni-plaintext\">0.13543589743590018</div></td></tr><tr><td>13</td><td><div class=\"dni-plaintext\">-0.03897954353340993</div></td></tr><tr><td>14</td><td><div class=\"dni-plaintext\">-0.17731008431411102</div></td></tr><tr><td>15</td><td><div class=\"dni-plaintext\">-0.24030671152304095</div></td></tr><tr><td>16</td><td><div class=\"dni-plaintext\">-0.08247055673614988</div></td></tr><tr><td>17</td><td><div class=\"dni-plaintext\">-0.47898448490240814</div></td></tr><tr><td>18</td><td><div class=\"dni-plaintext\">-0.9020715041856615</div></td></tr><tr><td>19</td><td><div class=\"dni-plaintext\">-1.3489730137363423</div></td></tr><tr><td colspan=\"2\"><i>(51 more)</i></td></tr></tbody></table>"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
"source": [
|
||||||
"Yahoo_Feed aapl = new(\"AAPL\", 100);\n",
|
"Yahoo_Feed aapl = new(\"AAPL\", 100);\n",
|
||||||
"TSeries close = aapl.Close; // close will get data from history\n",
|
"TSeries close = aapl.Close; // close will get data from history\n",
|
||||||
@@ -266,14 +239,33 @@
|
|||||||
"language": "C#",
|
"language": "C#",
|
||||||
"name": ".net-csharp"
|
"name": ".net-csharp"
|
||||||
},
|
},
|
||||||
"language_info": {
|
"polyglot_notebook": {
|
||||||
"file_extension": ".cs",
|
"kernelInfo": {
|
||||||
"mimetype": "text/x-csharp",
|
"defaultKernelName": "csharp",
|
||||||
"name": "C#",
|
"items": [
|
||||||
"pygments_lexer": "csharp",
|
{
|
||||||
"version": "9.0"
|
"aliases": [
|
||||||
},
|
"c#",
|
||||||
"orig_nbformat": 4
|
"C#"
|
||||||
|
],
|
||||||
|
"languageName": "C#",
|
||||||
|
"name": "csharp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aliases": [
|
||||||
|
"frontend"
|
||||||
|
],
|
||||||
|
"languageName": null,
|
||||||
|
"name": "vscode"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aliases": [],
|
||||||
|
"languageName": "KQL",
|
||||||
|
"name": "kql"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"nbformat": 4,
|
"nbformat": 4,
|
||||||
"nbformat_minor": 2
|
"nbformat_minor": 2
|
||||||
|
|||||||
+13
-7
@@ -6,20 +6,26 @@
|
|||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||||
<meta name="description" content="Description">
|
<meta name="description" content="Description">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/css/theme-simple.css">
|
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script>
|
<script>
|
||||||
window.$docsify = {
|
window.$docsify = {
|
||||||
name: 'QuanTAlib',
|
name: '',
|
||||||
repo: 'mihakralj/quantalib'
|
repo: '',
|
||||||
}
|
latex: {
|
||||||
|
inlineMath : [['$', '$'], ['\\(', '\\)']], // default
|
||||||
|
displayMath : [['$$', '$$']], // default
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-csharp.min.js"></script>
|
|
||||||
<!-- Docsify v4 -->
|
<!-- Docsify v4 -->
|
||||||
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
|
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
|
||||||
<script src="//cdn.jsdelivr.net/npm/docsify-themeable@0/dist/js/docsify-themeable.min.js"></script>
|
<!-- LaTeX display engine -->
|
||||||
<script src="//unpkg.com/@rakutentech/docsify-code-inline/dist/index.min.js"></script>
|
<script src="//cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
|
||||||
|
<!-- docsify-latex plugin -->
|
||||||
|
<script src="//cdn.jsdelivr.net/npm/docsify-latex@0"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+43
-32
@@ -34,28 +34,31 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
|
|||||||
|
|
||||||
⛔= Not implemented (yet)
|
⛔= Not implemented (yet)
|
||||||
|
|
||||||
| **BASIC TRANSFORMS** | **QuanTAlib** | **TA-LIB** | **Skender** | **Pandas TA** |
|
| **BASIC TRANSFORMS** | **QuanTAlib** | **TA-LIB** | **Skender** | **Pandas TA** | **Tulip** |
|
||||||
|--|:--:|:--:|:--:|:--:|
|
|--|:--:|:--:|:--:|:--:|:--:|
|
||||||
| ⭐ OC2 - (Open+Close)/2 |️ `.OC2` || CandlePart.OC2 ||
|
| ⭐ OC2 - (Open+Close)/2 |️ `.OC2` || CandlePart.OC2 ||
|
||||||
| ⭐ HL2 - Median Price | `.HL2` | MEDPRICE | CandlePart.HL2 | hl2 |
|
| ⭐ HL2 - Median Price | `.HL2` | MEDPRICE | CandlePart.HL2 | hl2 |
|
||||||
| ⭐ HLC3 - Typical Price | `.HLC3` | TYPPRICE | CandlePart.HLC3 | hlc3 |
|
| ⭐ HLC3 - Typical Price | `.HLC3` | TYPPRICE | CandlePart.HLC3 | hlc3 |
|
||||||
| ⭐ OHL3 - (Open+High+Low)/3 | `.OHL3` || CandlePart.OHL3 ||
|
| ⭐ OHL3 - (Open+High+Low)/3 | `.OHL3` || CandlePart.OHL3 ||
|
||||||
| ⭐ OHLC4 - Average Price | `.OHLC4` | AVGPRICE |️ CandlePart.OHLC4 | ohlc4 |
|
| ⭐ OHLC4 - Average Price | `.OHLC4` | AVGPRICE |️ CandlePart.OHLC4 | ohlc4 | avgprice |
|
||||||
| ⭐ HLCC4 - Weighted Price | `.HLCC4` | WCLPRICE | CandlePart.HLCC4 ||
|
| ⭐ HLCC4 - Weighted Price | `.HLCC4` | WCLPRICE | CandlePart.HLCC4 ||
|
||||||
| ⭐ MIDPOINT - Midpoint value | `MIDPOINT_Series` | MIDPOINT || midpoint |
|
| ⭐ MIDPOINT - Midpoint value | `MIDPOINT_Series` | MIDPOINT || midpoint |
|
||||||
| ⭐ MIDPRICE - Midpoint price | `MIDPRICE_Series` | MIDPRICE || midprice |
|
| ⭐ MIDPRICE - Midpoint price | `MIDPRICE_Series` | MIDPRICE || midprice |
|
||||||
| ⭐ MAX - Max value | `MAX_Series` | MAX |||
|
| ⭐ MAX - Max value | `MAX_Series` | MAX ||| max |
|
||||||
| ⭐ MIN - Min value | `MIN_Series` | MIN |||
|
| ⭐ MIN - Min value | `MIN_Series` | MIN ||| min |
|
||||||
| ⭐ SUM - Summation | `SUM_Series` | SUM |||
|
| ⭐ SUM - Summation | `SUM_Series` | SUM ||| sum |
|
||||||
| ⭐ ADD - Addition | `ADD_Series` | ADD |||
|
| ⭐ ADD - Addition | `ADD_Series` | ADD ||| add |
|
||||||
| ⭐ SUB - Subtraction | `SUB_Series` | SUB |||
|
| ⭐ SUB - Subtraction | `SUB_Series` | SUB ||| sub |
|
||||||
| ⭐ MUL - Multiplication | `MUL_Series` | MUL |||
|
| ⭐ MUL - Multiplication | `MUL_Series` | MUL ||| mul |
|
||||||
| ⭐ DIV - Division | `DIV_Series` | DIV |||
|
| ⭐ DIV - Division | `DIV_Series` | DIV ||| div |
|
||||||
|||||
|
|||||
|
||||||
| **STATISTICS & NUMERICAL ANALYSIS** | **QuanTAlib** | **TA-LIB** | **Skender** | **Pandas TA** |
|
| **STATISTICS & NUMERICAL ANALYSIS** |
|
||||||
|
||||||
|
||||||
| ⭐ BIAS - Bias | `BIAS_Series` ||| bias |
|
| ⭐ BIAS - Bias | `BIAS_Series` ||| bias |
|
||||||
| ⭐ CORR - Pearson's Correlation Coefficient | `CORR_Series` | CORREL | GetCorrelation ||
|
| ⭐ CORR - Pearson's Correlation Coefficient | `CORR_Series` | CORREL | GetCorrelation ||
|
||||||
| ⭐ COVAR - Covariance | `COVAR_Series` || GetCorrelation ||
|
| ⭐ COVAR - Covariance | `COVAR_Series` || GetCorrelation ||
|
||||||
|
| ⛔ DECAY - Linear Decay ||||| decay |
|
||||||
|
| ⛔ EDECAY - Exponential Decay ||||| edecay |
|
||||||
| ⭐ ENTROPY - Entropy | `ENTROPY_Series` ||| entropy |
|
| ⭐ ENTROPY - Entropy | `ENTROPY_Series` ||| entropy |
|
||||||
| ⭐ KURTOSIS - Kurtosis | `KURT_Series` ||| kurtosis |
|
| ⭐ KURTOSIS - Kurtosis | `KURT_Series` ||| kurtosis |
|
||||||
| ⭐ LINREG - Linear Regression | `LINREG_Series` || GetSlope ||
|
| ⭐ LINREG - Linear Regression | `LINREG_Series` || GetSlope ||
|
||||||
@@ -73,22 +76,23 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
|
|||||||
| ✔️ WMAPE - Weighted Mean Absolute Percent Error | `WMAPE_Series` ||||
|
| ✔️ WMAPE - Weighted Mean Absolute Percent Error | `WMAPE_Series` ||||
|
||||||
| ⭐ ZSCORE - Number of standard deviations from mean | `ZSCORE_Series` || GetStdDev | zscore |
|
| ⭐ ZSCORE - Number of standard deviations from mean | `ZSCORE_Series` || GetStdDev | zscore |
|
||||||
||||||
|
||||||
|
||||||
| **TREND INDICATORS & AVERAGES** | **QuanTAlib** | **TA-LIB** | **Skender** | **Pandas TA** |
|
| **TREND INDICATORS & AVERAGES** |
|
||||||
|
||||||
|
||||||
| ⛔ AFIRMA - Autoregressive Finite Impulse Response Moving Average |||||
|
| ⛔ AFIRMA - Autoregressive Finite Impulse Response Moving Average |||||
|
||||||
| ⭐ ALMA - Arnaud Legoux Moving Average | `ALMA_Series` || GetAlma | alma |
|
| ⭐ ALMA - Arnaud Legoux Moving Average | `ALMA_Series` || GetAlma | alma |
|
||||||
| ⛔ ARIMA - Autoregressive Integrated Moving Average |||||
|
| ⛔ ARIMA - Autoregressive Integrated Moving Average |||||
|
||||||
| ⭐ DEMA - Double EMA Average | `DEMA_Series` | DEMA | GetDema | dema |
|
| ⭐ DEMA - Double EMA Average | `DEMA_Series` | DEMA | GetDema | dema | dema |
|
||||||
| ⭐ EMA - Exponential Moving Average | `EMA_Series` | EMA | GetEma | ema |
|
| ⭐ EMA - Exponential Moving Average | `EMA_Series` | EMA | GetEma | ema | ema |
|
||||||
| ⛔ EPMA - Endpoint Moving Average ||| GetEpma ||
|
| ⛔ EPMA - Endpoint Moving Average ||| GetEpma ||
|
||||||
| ⛔ FRAMA - Fractal Adaptive Moving Average |||||
|
| ⛔ FRAMA - Fractal Adaptive Moving Average |||||
|
||||||
| ⛔ FWMA - Fibonacci's Weighted Moving Average |||| fwma |
|
| ⛔ FWMA - Fibonacci's Weighted Moving Average |||| fwma |
|
||||||
| ⛔ HILO - Gann High-Low Activator |||| hilo |
|
| ⛔ HILO - Gann High-Low Activator |||| hilo |
|
||||||
| ✔️ HEMA - Hull/EMA Average | `HEMA_Series` ||||
|
| ✔️ 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 |
|
| ⭐ HMA - Hull Moving Average | `HMA_Series` || GetHma | hma | hma |
|
||||||
| ⛔ HWMA - Holt-Winter Moving Average |||| hwma |
|
| ⛔ HWMA - Holt-Winter Moving Average |||| hwma |
|
||||||
| ✔️ JMA - Jurik Moving Average | `JMA_Series` ||| jma |
|
| ✔️ JMA - Jurik Moving Average | `JMA_Series` ||| jma |
|
||||||
| ⭐ KAMA - Kaufman's Adaptive Moving Average | `KAMA_Series` | KAMA | GetKama | kama |
|
| ⭐ KAMA - Kaufman's Adaptive Moving Average | `KAMA_Series` | KAMA | GetKama | kama | kama |
|
||||||
| ⛔ KDJ - KDJ Indicator (trend reversal) |||| kdj |
|
| ⛔ KDJ - KDJ Indicator (trend reversal) |||| kdj |
|
||||||
| ⛔ LSMA - Least Squares Moving Average |||||
|
| ⛔ LSMA - Least Squares Moving Average |||||
|
||||||
| ⭐ MACD - Moving Average Convergence/Divergence | `MACD_Series` | MACD | GetMacd | macd |
|
| ⭐ MACD - Moving Average Convergence/Divergence | `MACD_Series` | MACD | GetMacd | macd |
|
||||||
@@ -113,17 +117,20 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
|
|||||||
| ⭐ WMA - Weighted Moving Average | `WMA_Series` | WMA | GetWma | wma |
|
| ⭐ WMA - Weighted Moving Average | `WMA_Series` | WMA | GetWma | wma |
|
||||||
| ⭐ ZLEMA - Zero Lag EMA Average | `ZLEMA_Series` ||| zlma |
|
| ⭐ ZLEMA - Zero Lag EMA Average | `ZLEMA_Series` ||| zlma |
|
||||||
||||||
|
||||||
|
||||||
| **VOLATILITY INDICATORS** | **QuanTAlib** | **TA-LIB** | **Skender** | **Pandas TA** |
|
| **VOLATILITY INDICATORS** |
|
||||||
| ⭐ ADL - Chaikin Accumulation Distribution Line | `ADL_Series` | AD | GetAdl | ad |
|
||||||
|
||||||
| ⭐ ADOSC - Chaikin Accumulation Distribution Oscillator | `ADOSC_Series` | ADOSC| GetAdl | adosc |
|
| ⭐ ADL - Chaikin Accumulation Distribution Line | `ADL_Series` | AD | GetAdl | ad | ad |
|
||||||
| ⭐ ATR - Average True Range | `ATR_Series` | ATR | GetAtr | atr |
|
| ⭐ ADOSC - Chaikin Accumulation Distribution Oscillator | `ADOSC_Series` | ADOSC| GetAdl | adosc | adosc |
|
||||||
|
| ⭐ ATR - Average True Range | `ATR_Series` | ATR | GetAtr | atr | atr |
|
||||||
| ⭐ 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 || bbands |
|
||||||
| ⛔ CHAND - Chandelier Exit ||| GetChandelier ||
|
| ⛔ CHAND - Chandelier Exit ||| GetChandelier ||
|
||||||
| ⛔ CRSI - Connor RSI ||| GetConnorsRsi ||
|
| ⛔ CRSI - Connor RSI ||| GetConnorsRsi ||
|
||||||
|
| ⛔ CVI - Chaikins Volatility ||||| cvi |
|
||||||
| ⛔ DON - Donchian Channels ||| GetDonchian ||
|
| ⛔ DON - Donchian Channels ||| GetDonchian ||
|
||||||
| ⛔ FCB - Fractal Chaos Bands ||| GetFcb ||
|
| ⛔ FCB - Fractal Chaos Bands ||| GetFcb ||
|
||||||
|
| ⛔ FISHER - Fisher Transform ||| GetFcb || fisher |
|
||||||
| ⛔ HV - Historical Volatility |||||
|
| ⛔ HV - Historical Volatility |||||
|
||||||
| ⛔ ICH - Ichimoku ||| GetIchimoku ||
|
| ⛔ ICH - Ichimoku ||| GetIchimoku ||
|
||||||
| ⛔ KEL - Keltner Channels ||| GetKeltner ||
|
| ⛔ KEL - Keltner Channels ||| GetKeltner ||
|
||||||
@@ -137,23 +144,25 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
|
|||||||
| ⛔ UI - Ulcer Index |||||
|
| ⛔ UI - Ulcer Index |||||
|
||||||
| ⛔ VSTOP - Volatility Stop |||||
|
| ⛔ VSTOP - Volatility Stop |||||
|
||||||
||||||
|
||||||
|
||||||
| **MOMENTUM INDICATORS & OSCILLATORS** | **QuanTAlib** | **TA-LIB** | **Skender** | **Pandas TA** |
|
| **MOMENTUM INDICATORS & OSCILLATORS** |
|
||||||
|
||||||
|
||||||
| ⛔ AC - Acceleration Oscillator |||||
|
| ⛔ AC - Acceleration Oscillator |||||
|
||||||
| ⛔ ADX - Average Directional Movement Index || ADX | GetAdx ||
|
| ⛔ ADX - Average Directional Movement Index || ADX | GetAdx || adx |
|
||||||
| ⛔ ADXR - Average Directional Movement Index Rating || ADXR | GetAdx ||
|
| ⛔ ADXR - Average Directional Movement Index Rating || ADXR | GetAdx || adxr |
|
||||||
| ⛔ AO - Awesome Oscillator ||| GetAwesome ||
|
| ⛔ AO - Awesome Oscillator ||| GetAwesome || ao |
|
||||||
| ⛔ APO - Absolute Price Oscillator || APO |||
|
| ⛔ APO - Absolute Price Oscillator || APO ||| apo |
|
||||||
| ⛔ AROON - Aroon oscillator || AROON | GetAroon ||
|
| ⛔ AROON - Aroon oscillator || AROON | GetAroon || aroon |
|
||||||
| ⛔ BOP - Balance of Power || BOP | GetBop ||
|
| ⛔ BOP - Balance of Power || BOP | GetBop || bop |
|
||||||
| ⭐ CCI - Commodity Channel Index | `CCI_Series` | CCI | GetCci ||
|
| ⭐ CCI - Commodity Channel Index | `CCI_Series` | CCI | GetCci || cci |
|
||||||
| ⛔ CFO - Chande Forcast Oscillator |||||
|
| ⛔ CFO - Chande Forcast Oscillator |||||
|
||||||
| ⛔ CMO - Chande Momentum Oscillator || CMO | GetCmo ||
|
| ⛔ CMO - Chande Momentum Oscillator || CMO | GetCmo || cmo |
|
||||||
| ⛔ COG - Center of Gravity |||||
|
| ⛔ COG - Center of Gravity |||||
|
||||||
| ⛔ COPPOCK - Coppock Curve |||||
|
| ⛔ 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 ||
|
||||||
| ⛔ EFI - Elder Ray's Force Index ||| GetElderRay ||
|
| ⛔ EFI - Elder Ray's Force Index ||| GetElderRay ||
|
||||||
|
| ⛔ FOSC - Forecast oscillator ||||| fosc |
|
||||||
| ⛔ GAT - Alligator oscillator ||| GetGator ||
|
| ⛔ GAT - Alligator oscillator ||| GetGator ||
|
||||||
| ⛔ HURST - Hurst Exponent ||| GetHurst ||
|
| ⛔ HURST - Hurst Exponent ||| GetHurst ||
|
||||||
| ⛔ KRI - Kairi Relative Index |||||
|
| ⛔ KRI - Kairi Relative Index |||||
|
||||||
@@ -176,10 +185,12 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett
|
|||||||
| ⛔ WILLR - Larry Williams' %R || WILLR | GetWilliamsR ||
|
| ⛔ WILLR - Larry Williams' %R || WILLR | GetWilliamsR ||
|
||||||
| ⛔ WGAT - Williams Alligator |||||
|
| ⛔ WGAT - Williams Alligator |||||
|
||||||
||||||
|
||||||
|
||||||
| **VOLUME INDICATORS** | **QuanTAlib** | **TA-LIB** | **Skender** | **Pandas TA** |
|
| **VOLUME INDICATORS** |
|
||||||
|
||||||
|
||||||
| ⛔ AOBV - Archer On-Balance Volume |||||
|
| ⛔ AOBV - Archer On-Balance Volume |||||
|
||||||
| ⛔ CMF - Chaikin Money Flow |||||
|
| ⛔ CMF - Chaikin Money Flow |||||
|
||||||
| ⛔ EOM - Ease of Movement |||||
|
| ⛔ EOM - Ease of Movement ||||| emv |
|
||||||
|
| ⛔ KVO - Klinger Volume Oscilaltor ||||| kvo |
|
||||||
| ⭐ OBV - On-Balance Volume | `OBV_Series` | OBV | GetObv ||
|
| ⭐ OBV - On-Balance Volume | `OBV_Series` | OBV | GetObv ||
|
||||||
| ⛔ PRS - Price Relative Strength ||||
|
| ⛔ PRS - Price Relative Strength ||||
|
||||||
| ⛔ PVOL - Price-Volume |||||
|
| ⛔ PVOL - Price-Volume |||||
|
||||||
|
|||||||
Reference in New Issue
Block a user