Merge branch 'dev' into main

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